为什么启动类被【@SpringBootApplication】注解后,就会自动扫描其包内所有被【@Component】注解的类?

1、因为【@SpringBootApplication】又被【@ComponentScan】注解。

 2、注解【@ComponentScan】有一个属性【useDefaultFilters】,并且默认值为【true】。

3、Spring初始化时会将启动类加入上下文的【BeanFactory】中,然后进行后置处理器的处理。

4、后置处理器中有一个默认的配置类后置处理器。

 

 5、在配置类后置处理器中,有一个能否加入候选配置类集合的判断,判断依据为该类是否被【@Configuration】注解。

 

 6、在判定为配置类并加入候选集合后,会挨个执行方法【parse】和【doProcessConfigurationClass】进行处理。此时会通过配置类的元数据中获取所有的【ComponentScan】注解,然后针对每个【ComponentScan】注解,通过扫描解析器【componentScanParser】进行扫描并获取所有符合条件的【BeanDefinitionHolder】。

7、在对每个【ComponentScan】注解执行扫描解析时,会先建立一个Bean定义扫描器【ClassPathBeanDefinitionScanner】。此时就会询问该【ComponentScan】注解的【useDefaultFilters】属性值了。

 

8、当【useDefaultFilters】的属性值为真时,该会对该扫描器注册默认的过滤器。

 

 9、该注册过程的第一步就是对其【包含过滤器集合】---【includeFilters】增加对【@Component】注解的过滤。

 

 10、在后续对每个【ClassPath】下找到的类文件进行过滤时,所有被【@Component】注解过的类就会成为候选项。所以虽然是自动完成的,但最终还是通过Spring的扫描过滤器实现的。

 

11、所有被扫描出的类定义中,如果还有被【@Configuration】注解过的配置类,则对其递归调用【parse】方法,继续重复这个过程。

  配置类中被【@Bean】注解的【method】是通过后续的【retrieveBeanMethodMetadata】方法获取,并放入其【beanMethods】属性中。

12、通过遍历包路径下的类文件得到的配置类定义是如何加入到【BeanFactory】的呢?

  我们在对被【@Configuration】注解的启动类作为候选项进行解析的时候,会先创建一个解析器,该解析器会包含对Spring上下文的信息,同时也包括实现了接口【BeanDefinitionRegistry】的【BeanFactory】的引用。

  这样在扫描完成后,通过接口【BeanDefinitionRegistry】的方法【registerBeanDefinition】将获取到的候选【@Componet】Bean注册到Spring上下文的【BeanFactory】中。

 13、配置类中被【@Bean】注解的方法是如何加入到【BeanFactory】中Bean定义集合的呢?

  前面提到过在解析候选配置类时,除了将找到的被【@Component】注解的类定义加入【BeanFactory】中外,还通过方法【retrieveBeanMethodMetadata】,将配置类中被【@Bean】注解的方法收集到配置类【ConfigurationClass】的属性【beanMethods】中。

  在解析完配置类自身后,又建立了一个Bean定义读取器【ConfigurationClassBeanDefinitionReader】来对解析后生成的配置类进行处理,从而获取其通过方法定义的Bean定义。

  该Bean定义读取器和类文件解析器【ConfigurationClassParser】一样,建立时同样拥有对Spring上下文及实现了实现了【BeanDefinitionRegistry】接口的【BeanFactory】的引用。

   在处理过程中通过配置类对象的【getBeanMethods】方法,获取被【@Bean】注解的方法,然后调用方法【loadBeanDefinitionsForBeanMethod】进行解析、构建和注册。

  在将方法转换为Bean定义【BeanDefinition】后,然后执行接口【BeanDefinitionRegistry】的方法【registerBeanDefinition】,将其注入到【BeanFactory】的Bean定义集合中。

14、总体过程就是,Spring启动后先根据配置文件构建上下文运行环境,然后以启动类为起点扫描其包下的所有配置类,再扫描其它配置类,并形成【BeanDefinition】注册到【BeanFactory】中。然后遍历所有注册的配置类定义,将其在扫描过程中收集到的【@Bean】方法,转换为【BeanDefinition】并注册到【BeanFactory】。

  后续应该就是对所有的【BeanDefinition】,根据其顺序、依赖关系、优先级等属性,进行实例化并注册到【BeanFactory】中,这部分的实现过程并没有再深入跟踪。

posted @ 2019-12-27 21:10  StarkBrothers  阅读(2517)  评论(0编辑  收藏  举报