深入理解Spring bean 的创建过程

 2023-01-21
原文作者:i听风逝夜 原文地址:https://juejin.cn/post/7061895533819854861

前言

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

  1. 扫描过程 2. bean创建过程
  2. 容器扩展
  3. AOP源码分析
  4. 事务源码分析
  5. Spring JDBC源码分析
  6. 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.class, true, false);
       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.class, true, false);

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()的值。