• 为什么启动类被【@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】中,这部分的实现过程并没有再深入跟踪。

  • 相关阅读:
    html5 audio的语法以及属性和方法
    转自可可英语的文章,以激励我努力学习英语。
    Linux下怎么删除非空目录
    Unity脚本时间执行顺序
    一个高手很多同时又能学习英语的问答网站
    Unity中Time.deltaTime的含义及其应用
    用C++画心(转)
    web中将body占满整个页面的办法
    基于FPGA的LCD+CMOS视频采集显示使用小结
    基于iCamera测试500w摄像头-mt9p001,mt9p031,mt9p001模块小结
  • 原文地址:https://www.cnblogs.com/StarkBrothers/p/12109620.html
Copyright © 2020-2023  润新知