深入理解Spring(二)、Bean创建过程

>>强大,10k+点赞的 SpringBoot 后台管理系统竟然出了详细教程!

前言

深入理解Spring源码分为7小节,本小节为Spring源码第二小节,各个小节目录如下。

  1. 扫描过程

2.  bean创建过程

  1. 容器扩展
  2. AOP源码分析
  3. 事务源码分析
  4. Spring JDBC源码分析
  5. Spring常用设计模式

Bean二次收集

上一节说完了bean的收集过程,但那只是Spring的第一次收集,还有第二次,这个阶段收集必须实例化一些Bean才能完成,这个过程也是留给框架扩展用的,比如可能见过这样的注解@EnableXXXX,这中注解的背后往往都会向容器添加新的Bean,所以我们必须要了解。

看下AnnotationConfigApplicationContext的构造方法,scan我们不再需要说了,重要的是refresh,此方法是核心,很复杂。

public AnnotationConfigApplicationContext(String... basePackages) {
   this();
   scan(basePackages);
   refresh();
}

refresh下有很多方法,如下。

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
      /**
       * 不需要看
       */

      prepareRefresh();
      /**
       * 获取在本类的构造方法执行阶段实例化的DefaultListableBeanFactory,所有阶段都围绕这他
       */

      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      /**
       * 向ConfigurableListableBeanFactory中添加一些其他辅助类,如后处理器
       */

      prepareBeanFactory(beanFactory);
      try {
         /**
          * 这个方法用来扩展,这个过程没有子类重写他,不需要看
          */

         postProcessBeanFactory(beanFactory);
         StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process")
         /**
          * 这里也实现了Bean的收集,主要会执行ConfigurationClassPostProcessor
          * 这里是个循环收集过程
          */

         invokeBeanFactoryPostProcessors(beanFactory);
         /**
          * 收集所有BeanPostProcessors
          */

         registerBeanPostProcessors(beanFactory);
         beanPostProcess.end();
         initMessageSource();
         initApplicationEventMulticaster();
         onRefresh();
         registerListeners();
         //实例化剩余的Bean
         finishBeanFactoryInitialization(beanFactory);
         finishRefresh();
      } catch (BeansException ex) {
         if (logger.isWarnEnabled()) {
            logger.warn("Exception encountered during context initialization - " +
                  "cancelling refresh attempt: " + ex);
         }
         // Destroy already created singletons to avoid dangling resources.
         destroyBeans();
         // Reset 'active' flag.
         cancelRefresh(ex);
         // Propagate exception to caller.
         throw ex;
      } finally {
         // Reset common introspection caches in Spring's core, since we
         // might not ever need metadata for singleton beans anymore...
         resetCommonCaches();
         contextRefresh.end();
      }
   }
}

我们从第一个有用的方法开始看,也就是invokeBeanFactoryPostProcessors(),这个方法非常重要,他会调用所有实现了BeanDefinitionRegistryPostProcessor接口的类的postProcessBeanDefinitionRegistry()方法,其中最核心的一个实现类是ConfigurationClassPostProcessor,他可能会向容器添加新的bean,因为类中可能有@Import、@Bean这样的注解,那么总有一个类要负责这些注解的解析,那这个类就是他。

这个接口注释是这样描述的,"可以进行更多的bean定义",也就是说,除了在类上加入注解,还可以通过这个接口向容器添加更多的bean,比如下面这样。

@Component
public class TestA  implements BeanDefinitionRegistryPostProcessor{
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   }
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
      AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(TestB.class)
            .getBeanDefinition()
;
      registry.registerBeanDefinition("testBean",beanDefinition);
   }
}

而ConfigurationClassPostProcessor作的主要工作就是接着收集Bean,下面来看下具体是怎么做的。

执行所有BeanDefinitionRegistryPostProcessor

从invokeBeanFactoryPostProcessors()进入直接来到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(),这里做的第一件事是从现阶段收集到的bean列表中找出实现了BeanDefinitionRegistryPostProcessor接口的bean,并且还实现了PriorityOrdered接口(用来排序),在此时,唯一一个符合这个条件的就是ConfigurationClassPostProcessor,那么会调用getBean()实例化他,实例化后调用postProcessBeanDefinitionRegistry进行新的bean收集。

收集过后,容器中可能会增加同样实现了BeanDefinitionRegistryPostProcessor接口的类,那么Spring还要判断,如果这些类中有实现Ordered(用来排序)接口的,那么做同样的事,实例化他,并调用postProcessBeanDefinitionRegistry。

那么问题来了,如果这个时候还有新的类被添加到容器中,并且还有一些类是实现了BeanDefinitionRegistryPostProcessor接口,那怎么办?

依次收集呗,所以这里Spring通过一个while开始不停的套娃收集,这里的思路是,只要进入循环后,下一次的条件就是false,然后从现有的bean中重复上面的操作,如果发现某个bean没有被处理过,那么把下一次循环条件设置为true,然后再排序,在收集。

boolean reiterate = true;
while (reiterate) {
   reiterate = false;
   /**
    * 再次获取实现了BeanDefinitionRegistryPostProcessor接口的类,并且实例化
    * 这里也是个循环调用,直到所有bean中都收集完成了
    */

   postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.classtruefalse);
   for (String ppName : postProcessorNames) {
      if (!processedBeans.contains(ppName)) {
         currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
         processedBeans.add(ppName);
         reiterate = true;
      }
   }
   //排序
   sortPostProcessors(currentRegistryProcessors, beanFactory);
   registryProcessors.addAll(currentRegistryProcessors);
   //调用postProcessBeanDefinitionRegistry进行新的bean收集。
   invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
   currentRegistryProcessors.clear();
}

收集过后,会获取所有实现了BeanFactoryPostProcessor接口的类,会按照实现了PriorityOrdered、Ordered接口的优先级,依次调用他们的postProcessBeanFactory方法,这个方法位于BeanFactoryPostProcessor接口下,而BeanDefinitionRegistryPostProcessor又继承他。

这个方法作者是这样描述的,方法被调用时,所有bean定义都已加载,但没有被实例化,我们可以修改bean的属性,同样也可以增加新的bean,比如下面这样。

@Component
public class TestA  implements BeanDefinitionRegistryPostProcessor{
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(TestB.class)
            .getBeanDefinition()
;
      ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition("testBean",beanDefinition);
   }
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
   }
}

参数ConfigurableListableBeanFactory唯一的实现类是DefaultListableBeanFactory,拿到他后,我们可以为所欲为,因为DefaultListableBeanFactory是一个核心类,同样也可以注册Bean。

ConfigurationClassPostProcessor

上面说到了会调用ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry,这里才是重头戏。

代码很长,就不帖了。

收集可能存在新Bean的类

首先会遍历现阶段容器中所有bean,检测这个bean类上是否标有Configuration、Component、ComponentScan、Import、ImportResource注解,标有的话,把这个bean放入一个集合中,如果没有的话,还会检测类中方法上是不是标有@Bean注解,有的话,同样放到这个集合中。

还有个知识点是如果标有Configuration注解,并且proxyBeanMethods是true,那么未来会进行增强,也就是需要进行动态代理。

如果这样写,那么最终实例化的就是原始类,但如果proxyBeanMethods是true,那么最终类会由CGLIB代理一下,打印他的话是这个样子TestC$$EnhancerBySpringCGLIB$$8d32c824@6c2d4cc6

@Configuration(proxyBeanMethods = false)
public class TestC {
}

此刻Spring已经挑出来需要进一步处理的类了,下一步就是挨个解析了,这部分由ConfigurationClassParser解析,从名字就可以看出,叫"配置类解析"

另外这个过程是个递归过程。

处理内部类

首先会判断是不是标有Component注解,当然他的"子注解"也一样,如果标有的话,会先处理他的内部类,如果内部类上同样标有@Component或者他的"子注解",那么这个类最终也会被Spring收录到容器,同样内部类中还有内部类,这种套娃的形式,Spring也考虑到了,会通过递归处理。

if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
    processMemberClasses(configClass, sourceClass, filter);
}

收集属性

接着会判断有没有PropertySources注解,有的话封装成PropertySource添加到上下文的environment中,PropertySource就保存着如application.properties文件中的值,最后用于依赖注入。

这里还有一个知识点很重要,environment是在AnnotationConfigApplicationContext中创建的,那么这个变量是如何传递到ConfigurationClassPostProcessor中的呢?这就涉及到Aware接口了,放到后面说。

扫描新路径

接着会处理ComponentScans、ComponentScan注解,Spring拿到里面的值后,会重新使用上一章的方法,进如doScan进行扫描,扫描后会把扫描到的新Bean在走一遍这些流程。

处理Import

接着会处理@Import注解,这部分还是比较多的,因为@Import中的class可能分为以下三种情况。

  1. 实现了ImportSelector

  2. 实现了ImportBeanDefinitionRegistrar

  3. 独立类

简而言之这三种都可以收集新的bean,如果是第三种的话,那么新的bean名称就是他的完整路径,比如com.xxx.TestA,同样这个过程也是个递归收集过程,第二种情况会暂时先实例化后放入到一个集合中,并不会调用其中任何方法,将来才会调用,第一种和第三种暂时也不会放入到容器,而是先放入到一个集合中。

如果在TestA上标有@Import(TestB.class),在TestB上又@Import(TestA.class),这时候会发生死循环,那么Spring肯定也知道,他是通过ImportStack来完成的,比如处理TestA的时候,把TestA放进这个栈,如果在未来还要处理TestA,由于栈中已经存在了,就会抛出异常。

获取带有@Bean注解的方法

下面还要收集这个类中带有@Bean注解的方法,最终会把他封装为BeanMethod对象,添加到集合中,将来会调用这个方法,并把这个返回值放入到容器中。

Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
   configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

收集接口中的default方法

这里就更牛逼了,如果这个类实现了某个接口,并且这个接口中有标有@Bean注解的的default方法,那么Spring还是要收集,并且这也是个递归过程,也就是接口继承接口的时候,会一头钻到底。

@Bean
default public TestB print() {
   return new TestB();
}
private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
//获取这个类所有的接口
   for (SourceClass ifc : sourceClass.getInterfaces()) {
   //提取有被@Bean标有的default方法
      Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
      for (MethodMetadata methodMetadata : beanMethods) {
         if (!methodMetadata.isAbstract()) {
            configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
         }
      }
      //递归重新获取这个接口中所有被@Bean标有的default方法
      processInterfaces(configClass, ifc);
   }
}

处理父类

当本类处理完后,可能他的父类中同样有上面这些需求,Spring也要处理。但这不是递归过程,是个while过程,doProcessConfigurationClass就是上面说的所有过程,返回值是他的父类,没有的话会返回null。

 do {
      sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
 }
   while (sourceClass != null);

到这里这个过程就结束了,开始下一个过程

向容器添加新的bean

到这里,配置类已经解析完成了,类中所有标有@Bean的方法还有其他信息都已经提取好后封装成了ConfigurationClass,下一步就是读取这些信息,把能放进容器的都放进容器。

也就是下面这段,见名知意,加载BeanDefinitions从ConfigurationClass,这里注意有s,表明一个配置类中可能有很多个BeanDefinition准备要添加到容器。

private void loadBeanDefinitionsForConfigurationClass(
      ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)
 
{
   /**
    * 判断是否跳过
    */

   if (trackedConditionEvaluator.shouldSkip(configClass)) {
      String beanName = configClass.getBeanName();
      if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
         this.registry.removeBeanDefinition(beanName);
      }
      this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
      return;
   }
   /**
    * 判断这个类是不是被@Import导入的,
    * 如果是,那么会把他封装成BeanDefinitionHolder,添加到容器
    */

   if (configClass.isImported()) {
      registerBeanDefinitionForImportedConfigurationClass(configClass);
   }
   /**
    * 遍历这个类所有加了@Bean注解的方法
    */

   for (BeanMethod beanMethod : configClass.getBeanMethods()) {
      loadBeanDefinitionsForBeanMethod(beanMethod);
   }
   loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
   /**
    * 调用ImportBeanDefinitionRegistrar
    */

   loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

这里其实没有什么难的,逻辑比较多的还是在方法上收集信息的时候,因为@Bean注解上有initMethod、destroyMethod很多信息,还要提取Scope注解,判断是不是需要代理,但是总之,这些工作都是从各个地方收集信息并且封装为BeanDefinition,只是各个BeanDefinition的实现类可能不同。

在这里看下最后一行调用,上面我们说过,@Import的class如果实现了ImportBeanDefinitionRegistrar接口,那么暂时会把他实例化后放入集合,未来会调用,那么这里就是。

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
   registrars.forEach((importBeanDefinitionRegistrar, annotationMetadata) -> {
      importBeanDefinitionRegistrar.registerBeanDefinitions(annotationMetadata, this.registry, this.importBeanNameGenerator);
   });
}

ImportBeanDefinitionRegistrar也用来收集新的Bean

BeanPostProcessor

下面就是收集所有实现了BeanPostProcessor接口的类,这个接口很重要,知道钩子函数的可能对他更好理解一点,他就类似与钩子,本来程序是按照正常的轨道执行的,但是你突然在中间增加了一个函数,这个函数接收一个输入,也有返回值,这个返回值会传递给原本的下一个函数。

比如本来有A、C两个函数,A处理的结果会传递给C,但是突然在其中增加了函数B,函数的执行顺序变成了A->B->C,并且B也有输入和输出,A把处理的结果传递给了B,B在其中可以修改A的结果,最后传递给C,C此时可能还不知道数据已经被修改了。

而这就是BeanPostProcessor的作用,在里面充当了B的角色。

在refresh()下面registerBeanPostProcessors()方法就是收集所有实现了BeanPostProcessor接口的类,也就是收集所有钩子,未来在创建对象前后会调用。

下面这段代码就是在所有bean中获取实现了BeanPostProcessor接口的类,具体是怎么获取的,本章就不看了。

String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.classtruefalse);

finishBeanFactoryInitialization

这基本上是最后一步了,这里面会调用下面这段,注释的意思是实例化剩余的非懒加载的bean,为什么说剩余呢?因为在前面已经有一部分逻辑需要已经实例化过了,比如这个Bean实现了一个Spring必须要用的接口,在前面实例化了,懒加载的bean指的是当需要的时候才实例化。

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();

而上面代码中的逻辑是遍历所有Bean名称,判断这个Bean是否有实例化的资格,比如懒加载的Bean在这里是没有资格的,有的话调用getBean()实例化。

getBean

这个过程是非常复杂的,主要复杂的是解决依赖问题,还有构造方法的问题,最简单的是无参构造,如果有参数,那就麻烦了,Spring要看看能不能在现有的bean中找到符合这个构造方法参数的bean,在加上可能还要处理@Value。

我们直接从AbstractBeanFactory#doGetBean开始,这里是获取bean的开始。

第一步是转换名称,因为如果使用@Bean,那么这个bean可能会有多个别名,比如name1,name2,这些名称中第一个会作为最终的bean名称放在beanDefinitionMap中,还有一个aliasMap存放这别名映射,比如name2->name1,当获取name2的时候,会最转换成name1。

接下来这一步是关键,是解决依赖问题核心。

//如果已经有实例了
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
   /**
    * 如果Bean实现了FactoryBean,在这里可能返回他的getObject方法
    */

   beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

详细看下getSingleton()

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // Quick check for existing instance without full singleton lock
   /**
    * 如果有完整的Bean对象,则直接返回
    * 所有对象创建后,并且完成属性填充,都会放入到这里
    */

   Object singletonObject = this.singletonObjects.get(beanName);
   /**
    * 如果没有这个对象,判断这个对象是不是在循环依赖的创建过程中。
    */

   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      /**
       * 一般情况都为Null
       */

      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               /**
                * 获取这个对象提早曝光后的结果
                */

               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  /**
                   * 获取这个对象提早曝光后的ObjectFactory
                   * 如果在这里存在这个对象工厂,则从工厂获取对象,这是前面提早曝光的结果
                   */

                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     //实例对象
                     singletonObject = singletonFactory.getObject();
                     //放入到earlySingletonObjects,可能以后还会用到
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     //删除对象工厂,他的对象都有了,就不需要了
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

无依赖创建过程

下面说一下无依赖创建过程,现在假如要获取testA,那么第一次从缓存中获取肯定是没有的,那么接下来会判断在不在依赖循环中,这时候肯定是不在的。

接下来会判断这个bean有没有依赖,这个依赖指的是@DependsOn,如果有的话,会先实例化他的依赖,实例化依赖的过程同样是调用getBean(),和当前流程一样。

然后判断是不是单例,一般情况下是的。

然后进入到这里,getSingleton第二个参数是ObjectFactory,用于创建对象。

sharedInstance = getSingleton(beanName, () -> {
   try {
      /**
       * 在getSingleton中会调用到这里
       */

      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      destroySingleton(beanName);
      throw ex;
   }
});

getSingleton里面做了三件重要的事,第一件事是把当前正在创建的bean放入一个集合中,用于循环依赖检测,第二件事是调用传递过来的ObjectFactory的getObject()获取对象,第三件事是把创建好的对象放入到缓存,以后可以直接从缓存中取。

所以我们来看最重要的第二件事,进入createBean()方法。

createBean()中Spring并没有自己先去实例化这个对象,而是交给扩展接口。

    /**
    * 试图实例化后初始化,如果扩展接口没有实例化,那么Spring自己实例化,否则直接返回
    */

   Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
   if (bean != null) {
      return bean;
   }

这个接口叫InstantiationAwareBeanPostProcessor,我们可以自己实现,当创建对象时,Spring会先交给他,如果他返回null,那么Spring只能自己实例化了,否则调用所有实现了BeanPostProcessor接口的postProcessAfterInitialization()方法后进行返回,这也是Spring留给我们扩展用的。

现在假如没有任何类愿意实例化这个bean,那么Spring只能自己处理,进入到doCreateBean()中。

/**
 * 自己实例化
 */

Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;

doCreateBean()的第一句就是实例化对象。

/**
 * 创建对象,初始化对象
 */

instanceWrapper = createBeanInstance(beanName, mbd, args);

这一步就比较麻烦了,因为Spring要推断很多类型。但是现在只要知道这句执行后,我们的对象就创建成功了,但这也可能是个代理对象,Spring也没有在对象创建好后去代理,而是事先替换了要实例化的类,比如原本的类是com.Test,但是此刻通过反射实例化的是com.Test$$EnhancerBySpringCGLIB$$dded467a,这是在收集BeanDefinition过程中判断了如果这个类需要代理,那么就为先为他生成一个代理类。

创建完成后还会调用所有MergedBeanDefinitionPostProcessor接口。

接着会执行下面这句,第二个参数同样是ObjectFactory,这个叫提早曝光,对于无任何依赖的类来说,用不到,但是对依赖循环的时候有巨大用,我们把这里先称为“关键点1”

/**
 * 某个对象创建后,将他加入singletonFactories中,此时这个对象没有任何属性被填充,
 *  到了其他对象依赖这个对象的时候,从getEarlyBeanReference返回
 */

addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

接下来是填充属性,也叫依赖注入,如果没有任何属性,也没什么用,后面单独说这个方法。

/**
 * 填充属性
 */

populateBean(beanName, mbd, instanceWrapper);
/**
 * 调用对象的BeanNameAware、BeanClassLoaderAware、BeanFactoryAware
 */

exposedObject = initializeBean(beanName, exposedObject, mbd);

最后是初始化bean。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   /**
    * 调用对象的BeanNameAware、BeanClassLoaderAware、BeanFactoryAware(如果实现了的话)
    */

   invokeAwareMethods(beanName, bean);
   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      /**
       * 调用BeanPostProcessors的前置处理器尝试修改
       */

      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }
   try {
      /**
       * 调用bean的init方法
       */

      invokeInitMethods(beanName, wrappedBean, mbd);
   } catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      /**
       * 调用BeanPostProcessors的后置处理器尝试修改
       */

      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

这部分就结束了。

有依赖情况

下面来说有依赖情况,有依赖做的事就是属性填充,所以我们要了解populateBean()方法,populateBean()中会调用所有实现了InstantiationAwareBeanPostProcessor接口的postProcessProperties()方法,而具体完成属性填充的实现类是AutowiredAnnotationBeanPostProcessor,其他实现类会填充标有其他注解的属性,

进入AutowiredAnnotationBeanPostProcessor#postProcessProperties(),首先会调用findAutowiringMetadata找到需要自动注入的字段,这里主要是找Autowired、Value,找到之后放在InjectionMetadata对象中,此对象中有个集合,保存着InjectedElement,他表示单个需要被注入的字段信息。

InjectedElement的一个实现类也位于AutowiredAnnotationBeanPostProcessor下,叫AutowiredFieldElement,当调用他的inject方法表示对这个字段进行注入。

而在内部判断了如果这个字段是Class类型,那么直接调用开头的getBean()尝试从容器中获取,比较简单。

同样对于注入@Value的逻辑也在这里,只不过比较复杂,后续会单独分析。

依赖循环情况

现在假设TestA中需要注入TestB,TestB中需要注入TestA。

从getBean("testA")开始,同样会到达populateBean()方法填充testB,然后返回来再创建TestB,TestB创建成功后,同样会执行populateBean()填充TestA。

那么这时候不可能在创建testA,这样就成了死循环了。

还记得我们说的"关键点1"吗,当对象创建成功后,会在singletonFactories中保存一个对象工厂ObjectFactory,调用这个ObjectFactory的getObject()就可以在任何地方获取刚创建的对象。

这样当TestB在获取TestA的时候,发现singletonFactories中有个工厂可以获取到TestA,那么就直接调用他,最后会进入下面这个方法

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
   Object exposedObject = bean;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      List<SmartInstantiationAwareBeanPostProcessor> smartInstantiationAware = getBeanPostProcessorCache().smartInstantiationAware;
      for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
         exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
      }
   }
   return exposedObject;
}

他还是要调用所有实现了SmartInstantiationAwareBeanPostProcessor接口类的getEarlyBeanReference()尝试做最后的修改,目前我只发现他在AOP时候使用到了,所以本章暂时不考虑他。

那么这个方法返回的只是传递过来的对象。

这样依赖循环就解决了。

FactoryBean

我们回到最初,还有下面这一段需要解析。

/**
 * 如果Bean实现了FactoryBean,在这里可能返回他的getObject方法
 */

beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);

这种情况是当bean实现了FactoryBean接口的时候,getBean()会返回这个接口的getObject()的值。

- END -


原文始发于微信公众号(十四个字节):深入理解Spring(二)、Bean创建过程