抽丝剥茧spring源码(二)

书接上文,上文书说到invokeBeanFactoryPostProcessors()方法,这个方法十分重要,也相当复杂,我们继续分析。

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

e56a6e024b05f68bda4e559674fa7e5c21c.jpg

6cba84789fd9fedbf64e274a0d70ee867c4.jpg

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

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

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

b784538a8ec8e68f1c16b44b938d332463d.jpg

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

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

9f01d18f1a5ec059345dbd8f717e3a14fc0.jpg

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

c491a39f141b78018751ad23439f9d8fb5a.jpg

获取到的如下beanName:

4cefc1c882173ded371c4e7263dfe5cbf26.jpg

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

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

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

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

4ddcf5a1e476cd4a555d97b22ecda274b72.jpg

88b44513c8baaa5414089ff5225c92ac487.jpg

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

6112c1d35c87e0989b2e97e9621d398e805.jpg

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

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

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

5f16739b29b3da1d378c19d1f42bf87b2d6.jpg

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

09d55d9c73103a89a37b267dd355059e970.jpg

ce351f5080798aeafbcf7cc690a9840f830.jpg

48f60c82df6c889194e02a2506d96910b15.jpg

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

2376dce145a2d22a960e982c1dc61641eda.jpg

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

8cc44b3b949ce1bf948c032e98425e0e05e.jpg

asSourceClass():

ece31fce31a47153ac4bc405ed27fadd3ad.jpg

d1985c19f82dcb72a2d7700c5cf0e1a8a40.jpg

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

56039a1f256d5e95b60d3c99cad63c701b2.jpg

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

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

9bf0c5c18e35b0d2f97a57ebb9c9d434133.jpg

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

ad74e6de474e23086fa8b2a694abe4c75ac.jpg

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

98d68e70408f0fd1d3220d50712f183b29c.jpg

07d0b4bbd0aa3d973be3d8a6a888a0c09e7.jpg

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

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

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

1bfa59897ecd79e1e1865e6b8b34f1e5780.jpg

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

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

转载于:https://my.oschina.net/u/3759047/blog/3075533

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值