抽丝剥茧spring源码(二)

书接上文,上文书说到invokeBeanFactoryPostProcessors()方法,这个方法十分重要,也至关复杂,咱们继续分析。spring

首先看下在执行完invokeBeanFactoryPostProcessors()方法以后,容器中发生了哪些变化:post

上面框起来的部分就是执行这个方法以后容器中数据的变化,也就能初步知道这个方法作了什么了。这个方法主要是解析启动时构造方法传入的扫描类(在这个实例中是App.class),看这个类中是否存在@ComponentScan中,若是存在就会去扫描这个注解中配置的须要扫描的包路径下面的类,被扫描的包下面的类中包含@Component注解的类会将注入到容器中。也就发生了上面图中的变化。这个就是这个方法主要作的事情。this

上面咱们初步知道了这个方法所作的事情,那么咱们经过代码来看下spring是如何处理的。spa

  • 这个方法咱们主要主要看第一行代码,PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors()方法,这个方法是核心处理逻辑,这个方法比较复杂,咱们一点点来看下。

下面咱们就来一点点分析PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors()方法。3d

  • 下面方法是处理咱们自定义的实现了BeanFactoryPostProcessor接口的实现类,执行其默认方法,这个咱们先不用管,后续聊。

  • 重点来了,下面的第一行方法是从容器中获取BeanDefinitionRegistryPostProcessor类型的处理器类的名字。咱们看到了它获取到了什么?

获取到的以下beanName:component

这个名字是否是有点熟悉呢?没错,它就是在咱们以前说过的初始化AnnotatedBeanDefinitionReader实例的时候所注入的内置处理器ConfigurationClassPostProcessor。对象

beanFactory.getBeanNamesForType()方法具体处理逻辑咱们在后续博文中会详细说明。blog

咱们继续看本方法。获取到postProcessorNames[]以后,会调用getBean()方法取出其bean的实例,add到currentRegistryProcessors和processedBeans集合中。排序

  • 接下来会执行下面的逻辑,前两行是对取出的处理器类进行排序,重点在第三行invokeBeanDefinitionRegistryPostProcessors():

其就是执行了每一个处理器类的postProcessBeanDefinitionRegistry()方法,这里只处理ConfigurationClassPostProcessor类的这个方法。这个方法很复杂,咱们看下具体实现:接口

首先会从容器中取出全部bean,而后取出类上存在@Configuration、@Component、@ComponentScan、@Import、@ImportResource注解的的bean,add到configCandidates临时变量中。

其中ConfigurationClassUtils.checkConfigurationClassCandidate()方法处理咱们在以后博文中会详细解析。

  • 下面方法是排序,不重要。

  • 下图是核心的部分。那么咱们就来看下parse()方法,ConfigurationClassParser.parse():

这个方法入参configCandidate其实就是App.class的包装类型BeanDefinitionHolder。随后调用其内部的parse方法:

也就是调用processConfigurationClass()方法,这个方法的参数类型是ConfigurationClass,这个类中封装了元数据信息,资源描述,bean名字。下面咱们就看下processConfigurationClass()方法,这个方法中asSourceClass()和doProcessConfigurationClass()是比较重要的。

asSourceClass():

看上面的代码很清楚,这个方法就是获取App.class的注解并循环处理,咱们App.class上的注解就一个@ComponentScan,而后会调用validateAnnotation()方法,这个方法会经过反射机制调用ComponentScan注解类里定义的方法,以下:具体验证了什么还不懂。

最后asSourceClass方法会将App.class封装成SourceClass对象返回。

  • 接下来看doProcessConfigurationClass()方法作了什么,下面是这个方法中的核心部分之一,咱们看这块处理了什么?这块会取出App.class中全部的@ComponentScan注解,而后经过this.componentScanParser.parse()方法处理当前@ComponentScan注解,componentScanParser就是ComponentScanAnnotationParser类的实例。

下面看下prase()方法,这个方法主要是处理App.class的@ComponentScan注解的方法配置值,有则取出,没有则设置默认值,包括includeFilters、excludeFilters、lazyInit、basePackage等,取出其中最重要的一行代码以下:

scanner是ClassPathBeanDefinitionScanner类型对象,咱们看下这行代码作了什么?

主要是循环处理@ComponentScan里配置的包路径,也就是basePackages。其中上图红框中的两个方法是主要的处理方法:

findCandidateComponents()方法主要是取出当前包内全部包含@Component注解的类。

registerBeanDefinition()方法就是调用了DefaultListableBeanFactory类的registerBeanDefinition()方法,如下是这个方法的片断:

这个方法在第一节已经说明了,你们应该很熟悉了,就是将扫描出来的beanClass注入到bean工厂中(beanDefinitionMap和beanDefinitionNames)。以上就是本节开始说的容器中发生变化的处理逻辑,也就是为何注解了@Component的类能注入到bean工厂的缘由了。

上面我只说明了doProcessConfigurationClass()方法中的一个重要的处理逻辑(扫描须要扫描的包下全部须要注入到容器中的bean,完成注入),可是doProcessConfigurationClass()方法中还有一些重要的处理逻辑,好比对注解了@Import、@ImportSource等的beanClass是如何处理的,对beanClass中存在的内部类是如何处理的,等等这些内容是咱们下一节重点说明的。想知道spring是如何处理这部份内容的,请关注我下一篇关于spring的博文。

相关文章
相关标签/搜索