书接上文,上文书说到invokeBeanFactoryPostProcessors()方法,这个方法十分重要,也至关复杂,咱们继续分析。spring
首先看下在执行完invokeBeanFactoryPostProcessors()方法以后,容器中发生了哪些变化:post
上面框起来的部分就是执行这个方法以后容器中数据的变化,也就能初步知道这个方法作了什么了。这个方法主要是解析启动时构造方法传入的扫描类(在这个实例中是App.class),看这个类中是否存在@ComponentScan中,若是存在就会去扫描这个注解中配置的须要扫描的包路径下面的类,被扫描的包下面的类中包含@Component注解的类会将注入到容器中。也就发生了上面图中的变化。这个就是这个方法主要作的事情。this
上面咱们初步知道了这个方法所作的事情,那么咱们经过代码来看下spring是如何处理的。spa
下面咱们就来一点点分析PostProcessorRegistrationDelegate类的invokeBeanFactoryPostProcessors()方法。3d
获取到的以下beanName:component
这个名字是否是有点熟悉呢?没错,它就是在咱们以前说过的初始化AnnotatedBeanDefinitionReader实例的时候所注入的内置处理器ConfigurationClassPostProcessor。对象
beanFactory.getBeanNamesForType()方法具体处理逻辑咱们在后续博文中会详细说明。blog
咱们继续看本方法。获取到postProcessorNames[]以后,会调用getBean()方法取出其bean的实例,add到currentRegistryProcessors和processedBeans集合中。排序
其就是执行了每一个处理器类的postProcessBeanDefinitionRegistry()方法,这里只处理ConfigurationClassPostProcessor类的这个方法。这个方法很复杂,咱们看下具体实现:接口
首先会从容器中取出全部bean,而后取出类上存在@Configuration、@Component、@ComponentScan、@Import、@ImportResource注解的的bean,add到configCandidates临时变量中。
其中ConfigurationClassUtils.checkConfigurationClassCandidate()方法处理咱们在以后博文中会详细解析。
这个方法入参configCandidate其实就是App.class的包装类型BeanDefinitionHolder。随后调用其内部的parse方法:
也就是调用processConfigurationClass()方法,这个方法的参数类型是ConfigurationClass,这个类中封装了元数据信息,资源描述,bean名字。下面咱们就看下processConfigurationClass()方法,这个方法中asSourceClass()和doProcessConfigurationClass()是比较重要的。
asSourceClass():
看上面的代码很清楚,这个方法就是获取App.class的注解并循环处理,咱们App.class上的注解就一个@ComponentScan,而后会调用validateAnnotation()方法,这个方法会经过反射机制调用ComponentScan注解类里定义的方法,以下:具体验证了什么还不懂。
最后asSourceClass方法会将App.class封装成SourceClass对象返回。
下面看下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的博文。