源碼調試以spring boot 1.5.8.release爲例
Spring IOC容器初始化主要有以下幾個步驟
1、資源定位:找到配置文件。
2、BeanDefinition載入和解析
3、BeanDefinition註冊
4、實例化bean和依賴注入 (不在本篇討論範圍,該內容總結請看【十八】Spring IOC 總結之getBean主流程和各個擴展點總結)
而這一系列的操作種的前三步在SpringBoot中都是在AbstractApplicationContext#invokeBeanFactoryPostProcessors方法中完成的,該方法的源碼導讀請看以前寫的這篇:【四】Spring源碼分析之啓動主流程---AbstractApplicationContext的refresh方法 只是對該方法做了一個簡單介紹而已。
這個invokeBeanFactoryPostProcessors方法寫的很噁心,裏面是調用了ConfigurationClassPostProcessor的processConfigBeanDefinitions方法真正完成的資源定位、BeanDefinition載入和解析、BeanDefinition註冊,該方法源碼導讀請看以前寫的這篇:【八】Spring源碼分析之掃描註冊Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法
本篇主要是總結一下SpringBoot怎麼做定位資源,主要的3中定位資源的方式
這裏涉及到常規的Spring Boot項目中有3種定位方式:
1.掃主類(就是有註解@SpringBootApplication這個類)所在包的路徑
2.SPI擴展機制實現的自動裝配(比如各種starter)
3.@Import註解指定的類。
上面已經提到入口是ConfigurationClassPostProcessor的processConfigBeanDefinitions
這裏面是調用ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)方法來做的定位
該方法中主要是兩個事:
1.繼續調用本類的其他parse方法做定位,最終的邏輯是在doProcessConfigurationClass方法中。
該方法包含了兩種定位資源的方式
掃描springboot的有@SpringBootApplication註解的那個啓動類所在的路徑和對啓動類的@Import註解的處理2.processDeferredImportSelectors方法加載默認的配置(對springboot項目來說這裏就是自動裝配的入口了)
一、ConfigurationClassParser#doProcessConfigurationClass方法
該方法就是掃描springboot的有@SpringBootApplication註解的那個啓動類所在的路徑
1.首先遞歸處理啓動類的內部類,我們一般不會在啓動類寫內部類,就不debug這個了
2.對 @PropertySource 註解的屬性配置進行處理,這個我也沒有觸發到
解析該註解並將該註解指定的properties配置文件中的值存儲到Spring的 Environment中,Environment接口提供方法去讀取配置文件中的值,參數是properties文件中定義的key值。
3.對 @ComponentScan 註解進行處理(該註解在@SpringBootApplication註解中)
1.掃描啓動類所在的包,找到所有的@Component註解修飾的bean,並註冊到BeanDefinitionMap中
這裏就是從basePackage中掃描類並解析成ScannedGenericBeanDefinition然後註冊
主要邏輯的實現入口在ClassPathBeanDefinitionScanner#doScan
2.檢查該bean是否是ConfigurationClass(是否有configuration/component兩個註解)
如果是,遞歸查找該類相關聯的配置類。
(相關的配置類:比如@Configuration中的@Bean定義的bean。或者在有@Component註解的類上繼續存在@Import註解)
4.遞歸處理啓動類中的@Import,並加載該註解指定的配置類。
這裏說一下,@SpringBootApplication註解中包含@EnableAutoConfiguration註解,
而@EnableAutoConfiguration註解
包含@Import(EnableAutoConfigurationImportSelector.class)和@AutoConfigurationPackage這兩個註解是重點
5.處理啓動類中的@ImportResource註解,這裏沒有觸發
6.處理啓動類中的@Bean註解,這裏沒有觸發
7.處理啓動類實現的接口方法,並沒有觸發
8.處理啓動類的父類,並沒有觸發
二、processDeferredImportSelectors方法加載默認的配置
該方法就是通過啓動類的@Import加載各個jar下META-INF/spring.factories的自動配置類並註冊
對springboot項目來說這裏就是自動裝配的入口了
1.該方法裏面會調用EnableAutoConfigurationImportSelector的父類AutoConfigurationImportSelector的selectImports方法
1.獲取所有的自動配置類(META-INF/spring.factories中配置的key爲org.springframework.boot.autoconfigure.EnableAutoConfiguration的類)
2.排除的自動裝配類(springboot的主類上 @SpringBootApplication(exclude = {com.demo.starter.config.DemoConfig.class})指定的排除的自動裝配類)
3.過濾掉不需要裝配的類。過濾的邏輯有很多,比如我們常用的@ConditionXXX註解
4.返回需要自動配置類的全名
2.然後用ConfigurationClassParser#doProcessConfigurationClass方法講這些自動配置類加載並註冊