SpringloC容器的依赖注入源码解析(6)—— doCreateBean之处理@Autowired以及@Value标签

本文阅读 5 分钟
首页 代码,Java 正文

进入到上面的applyMergedBeanDefinitionPostProcessors方法里:

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) { 
   for (BeanPostProcessor bp : getBeanPostProcessors()) { 
      if (bp instanceof MergedBeanDefinitionPostProcessor) { 
         MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
         // 重点关注AutowiredAnnotationBeanPostProcessor,该类会把@Autowired等标记的
         // 需要依赖注入的成员变量或者方法实例给记录下来,方便后续populateBean使用
         bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
      }
   }
}

其中实现了postProcessMergedBeanDefinition方法的一个实现类MergedBeanDefinitionPostProcessor是要分析的重点 img img 构造方法:

public AutowiredAnnotationBeanPostProcessor() { 
   this.autowiredAnnotationTypes.add(Autowired.class);
   this.autowiredAnnotationTypes.add(Value.class);
   try { 
      this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
            ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
      logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
   }
   catch (ClassNotFoundException ex) { 
      // JSR-330 API not available - simply skip.
   }
}

把Autowired和Value标签加入到类型为Set的autowiredAnnotationTypes里。

当BeanName是自定义的WelcomeController时,从applyMergedBeanDefinitionPostProcessors方法的postProcessMergedBeanDefinition处进入断点:

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { 
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}

findAutowiringMetadata是寻找被注解的元数据:

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) { 
   // Fall back to class name as cache key, for backwards compatibility with custom callers.
   String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
   // Quick check on the concurrent map first, with minimal locking.
   // 从容器中查找是否有给定类的autowire相关注解元信息
   InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
   if (InjectionMetadata.needsRefresh(metadata, clazz)) { 
      synchronized (this.injectionMetadataCache) { 
         metadata = this.injectionMetadataCache.get(cacheKey);
         if (InjectionMetadata.needsRefresh(metadata, clazz)) { 
            if (metadata != null) { 
               metadata.clear(pvs);
            }
            metadata = buildAutowiringMetadata(clazz);
            // 将得到的给定类autowire相关注解源信息存储在容器缓存中
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}

该方法扫描到类里的属性或者方法有对应的注解,就会将其封装起来,最终封装成InjectionMetadata实例返回,进入到InjectionMetadata里: img 其中包含了哪些需要注入的元素,以及元素要注入到哪个目标类中,targetClass代表目标bean的class对象,injectedElements保存的是需要被注入的元素,即被Autowired或Value注解的属性或方法,checkedElements里面只保存了由Spring默认处理的属性、方法。

  injectedElements集合的泛型是InjectedElement,保存单个InjectedElement的值 img member用于保存被Autowired、Value注解标记的属性,isField用来决定member是Field还是方法,PropertyDescriptor可以对属性反射读写操作

回到findAutowiringMetadata方法,cacheKey是metadata在容器缓存中的名字,获取到了之后会先在容器缓存里查一下先前有没有获取到InjectionMetadata对象,之后会执行needsRefresh方法

public static boolean needsRefresh(@Nullable InjectionMetadata metadata, Class<?> clazz) { 
   return (metadata == null || metadata.targetClass != clazz);
}

该方法判断是否需要重新去扫描获取bean,如果不需要就会直接从缓存里返回先前注册的metadata实例。

在 if 里用到了双重锁检查机制,最终会调用

metadata = buildAutowiringMetadata(clazz);

创建出metadata来,进入到buildResourceMetadata:

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) { 
   if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { 
      return InjectionMetadata.EMPTY;
   }

   List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
   Class<?> targetClass = clazz;

   do { 
      final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
      // 收集被@Autowired或者@Value标记的Field
      // 利用反射机制获取给定类中所有的声明字段,获取字段上的注解信息
      ReflectionUtils.doWithLocalFields(targetClass, field -> { 
         MergedAnnotation<?> ann = findAutowiredAnnotation(field);
         if (ann != null) { 
            if (Modifier.isStatic(field.getModifiers())) { 
               if (logger.isInfoEnabled()) { 
                  logger.info("Autowired annotation is not supported on static fields: " + field);
               }
               return;
            }
            boolean required = determineRequiredStatus(ann);
            // 将当前字段元信息封装,添加在返回的集合中
            currElements.add(new AutowiredFieldElement(field, required));
         }
      });

      ReflectionUtils.doWithLocalMethods(targetClass, method -> { 
         Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
         if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { 
            return;
         }
         MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
         if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { 
            if (Modifier.isStatic(method.getModifiers())) { 
               if (logger.isInfoEnabled()) { 
                  logger.info("Autowired annotation is not supported on static methods: " + method);
               }
               return;
            }
            if (method.getParameterCount() == 0) { 
               if (logger.isInfoEnabled()) { 
                  logger.info("Autowired annotation should only be used on methods with parameters: " +
                        method);
               }
            }
            boolean required = determineRequiredStatus(ann);
            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
            currElements.add(new AutowiredMethodElement(method, required, pd));
         }
      });

      elements.addAll(0, currElements);
      targetClass = targetClass.getSuperclass();
   }
   while (targetClass != null && targetClass != Object.class);

   return InjectionMetadata.forElements(elements, clazz);
}

首先看一下该类是否有资格成为被Autowired或Value标记的候选类,主要是看一下class对象是不是普通的class,即这两个注解在这个class里有没有表示别的意思,判断逻辑如下:

public static boolean isCandidateClass(Class<?> clazz, String annotationName) { 
   if (annotationName.startsWith("java.")) { 
      return true;
   }
   if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) { 
      return false;
   }
   return true;
}

注解有java开头的注解就算是候选者;如果clazz是以java.打头或是Order类型的,则标签不会起作用,不能算做候选者

回到AutowiredAnnotationBeanPostProcessor.java的buildAutowiringMetadata方法 img 之后会通过循环来遍历class里面的属性元素以及方法元素,不管是何种元素都会执行findAutowiredAnnotation方法收集被Aotowired或Value标记的Field

进入到findAutowiredAnnotation方法里:

@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) { 
   MergedAnnotations annotations = MergedAnnotations.from(ao);
   for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { 
      MergedAnnotation<?> annotation = annotations.get(type);
      if (annotation.isPresent()) { 
         return annotation;
      }
   }
   return null;
}

isPresent方法判断是否被两种标签修饰,是的话将标记信息返回

回到buildAutowiringMetadata, img 之后判断Field是否是静态的,是的话会抛异常,因为静态Field不支持注入

之后再会获得Autowired里面的require属性

boolean required = determineRequiredStatus(ann);

获取到相关信息之后就会将field和required属性添加到list里面

currElements.add(new AutowiredFieldElement(field, required));

之后就会把收集到的被注解标记的属性以及方法实例,存储到集合中 img

最后返回:

return InjectionMetadata.forElements(elements, clazz);

进入到forElements方法里:

public static InjectionMetadata forElements(Collection<InjectedElement> elements, Class<?> clazz) { 
   return (elements.isEmpty() ? InjectionMetadata.EMPTY : new InjectionMetadata(clazz, elements));
}

该方法会将收集到的被标记的元素放入到新创建的InjectionMetadata实例里

img

回到findAutowiringMetadata, img 最后将metadata存储到缓存里

回到postProcessMergedBeanDefinition方法

@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) { 
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   metadata.checkConfigMembers(beanDefinition);
}

在获取到了metadata之后,会调用checkConfigMembers方法,进入到方法里:

public void checkConfigMembers(RootBeanDefinition beanDefinition) { 
   Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
   for (InjectedElement element : this.injectedElements) { 
      Member member = element.getMember();
      if (!beanDefinition.isExternallyManagedConfigMember(member)) { 
         beanDefinition.registerExternallyManagedConfigMember(member);
         checkedElements.add(element);
         if (logger.isTraceEnabled()) { 
            logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
         }
      }
   }
   this.checkedElements = checkedElements;
}

会把需要spring容器用默认策略注入的injectedelements集合给保存到前面说的checkedElements里,这样就完成了收集被Autowired和Value标记的属性和方法,有了实例之后就能通过调用其inject方法在合适的时候进行属性值的注入

回到doCreateBean img

本文为互联网自动采集或经作者授权后发布,本文观点不代表立场,若侵权下架请联系我们删帖处理!文章出自:https://wangjiawei.blog.csdn.net/article/details/121442213
-- 展开阅读全文 --
安全面试之XSS(跨站脚本攻击)
« 上一篇 07-24

发表评论

成为第一个评论的人

热门文章

标签TAG

最近回复