java spring框架refresh() 过程 之 源码分析@Resource和@Autowired

refresh过程步骤太多了,今天基于常见的@Resource和@Autowired注解,阅读源码,分析异同。

环境   jdk1.8 、 spring-? 5.1.3  基于AnnotationConfigApplicationContext的Class数组构造:

public AnnotationConfigApplicationContext(Class... annotatedClasses) {
   this();
   register(annotatedClasses);
   refresh();
}

方法抽象入口在 AbstractAutowireCapableBeanFactory类的ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName),(详细路径在 refresh() -> finishBeanFactoryInitialization()->...后面自己找,写不下了)

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第1张图片

方法实现:

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第2张图片

CommonAnnotationBeanPostProcessor类(处理resource注解)的实现为 :
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   //寻找@Resource下的元数据
   InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
   try {
   //具体注入方法
      metadata.inject(bean, beanName, pvs);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
   }
   return pvs;
}
AutowiredAnnotationBeanPostProcessor类(处理autowired注解)的实现为 :
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
   //寻找@Autowired下的元数据
   InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
   try {
   //具体注入方法
      metadata.inject(bean, beanName, pvs);
   }
   catch (BeanCreationException ex) {
      throw ex;
   }
   catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
   }
   return pvs;
}

InjectionMetadata 类 inject()方法的实现:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
   //checkedElements 就是检查到的  @Resource或者@Autowired下的属性或者方法(众所周知,@Resource和@Autowired都可以加载字段或者方法上)
   Collection checkedElements = this.checkedElements;
   Collection elementsToIterate =
         (checkedElements != null ? checkedElements : this.injectedElements);
   if (!elementsToIterate.isEmpty()) {
      for (InjectedElement element : elementsToIterate) {
         if (logger.isTraceEnabled()) {
            logger.trace("Processing injected element of bean '" + beanName + "': " + element);
         }
         //如果不为空,就执行相应的InjectedElement类(子类)的inject()方法
         element.inject(target, beanName, pvs);
      }
   }
}

对于Resource注解 element.inject() 的实现类就是InjectedElement(属性(field)和方法(method)都在一个inject()方法里)


对于Autowired注解 属性在 AutowiredFieldElement中实现 , 方法在AutowiredMethodElement中实现。

对于Resource注解,如果没有指定name,判断字段名存在于beanFactory中,再以字段名为bean名称 执行上面的方法,  否则就执行下面的

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第3张图片

对于Autowired注解执行此方法:

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第4张图片

其实就是相同的方法。

如果没有其他条件限制,最后会到下面的方法中:

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第5张图片

可以看到上面方法的具体逻辑是,根据需要注入的Class的Type寻找到此Type的所有bean的名称。

下面的方法:

:! isSelfReference 排除当前类的bean名称

:isAutowireCandidate ,核心实现:检查预选,从bean名称数组中挑选出@Qualifier的value的bean名称

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第6张图片

具体实现就是拿到@Qualifier的value进行判断,过滤掉非value的bean名称,这也是为什么@Autowired 可以和@Qualifier(value = "??")联合使用,起到确定唯一bean的作用。

然后回到doResolveDependency()方法中。

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第7张图片

对于required 为true的属性或者方法,bean为空就抛NoSuchBeanDefinitionException异常,如果bean数量大于一,会在determineAutowireCandidate()方法中进行primary,priority,以及通过字段名匹配bean名称 等操作再次判断,还是确定不了就抛NoUniqueBeanDefinitionException异常。

最后总结几点,网上没有的几点。

1、Resource 和 Autowired除了可以通过name和 @Qualifier(@Qualifier是通用的)的value 之外, 还可以通过字段名或者方法参数名来确定唯一bean名称

java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第8张图片像这样。等同于java spring框架refresh() 过程 之 源码分析@Resource和@Autowired_第9张图片

Resource:是在 autowireResource()方法中对字段名是否存在于beanFactory中作了判断,存在就以字段名为bean名称寻找唯一bean

对 Autowired:详情请看源码中的 DefaultListableBeanFactory类的doResolveDependency()方法中的determineAutowireCandidate()方法。 如果匹配到的bean数量大于一,则有一个与字段名判断的过程,选择和字段名相同的bean

2、Resource 和 Autowired作用在setter方法上,这里的setter方法并不是规定名字必须叫setxxx的方法,只是个赋值方法,根据规范通常用生成的set方法而已

3、什么ByName ,ByType注入,那是Bean注解的autowire属性的值和 Resource 、 Autowired无关

你可能感兴趣的:(spring,java)