為什么啟動類被【@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】中,這部分的實現過程並沒有再深入跟蹤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM