之前對SpringBoot的自動配置原理進行了較為詳細的介紹(https://www.cnblogs.com/stm32stm32/p/10560933.html),接下來就對自動配置進行源碼調試,探究下這個配置過程中各參數的情況。
這里對AutoConfigurationImportSelector類的selectImports()方法打了4處斷點,將着重對這4處進行調試。
第一處斷點:
該方法的源碼如下:
這一步就是將META-INF/spring-autoconfigure-metadata.properties文件中的鍵值對放入AutoConfigurationMetadataLoader的內部類PropertiesAutoConfigurationMetadata的Properties對象中,共有485個元素。
第二處斷點:
這個方法的源碼如下:
其中的name就是org.springframework.boot.autoconfigure.EnableAutoConfiguration類:
下面的方法中的metadata.getAnnotationAttributes(name, true)獲取到的值如下:
這里還利用斷言進行attributes是否為null判斷,若為null,則提示No auto-configuration attributes found. Is com.SpringbootApplication annotated with EnableAutoConfiguration ?
最終得到的attributes為:
第三處斷點:
getCandidateConfigurations方法定義如下:
其中的getSpringFactoriesLoaderFactoryClass()返回的是EnableAutoConfiguration.class。
進入loadFacotryNames()方法進行調試:
factoryClassName的值為org.springframework.boot.autoconfigure.EnableAutoConfiguration。
常量FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"。
下面的方法通過類加載器獲取jar包中所有META-INF/spring.factories並獲取其中的內容:
最后的urls包含掃描到3個jar包中有spring.factories文件:
接下來對urls進行3次遍歷:
第一次遍歷的文件路徑url=jar:file:/C:/Users/Alan/.m2/repository/org/springframework/boot/spring-boot/1.5.17.RELEASE/spring-boot-1.5.17.RELEASE.jar!/META-INF/spring.factories
通過Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));得到的properties對象的大小為7:
因為上述properties並不存在org.springframework.boot.autoconfigure.EnableAutoConfiguration的key,
所以String factoryClassNames = properties.getProperty(factoryClassName);得到的factoryClassNames為null
此時存放自動配置類的list集合result的大小仍然為0。
第二次遍歷的文件路徑url=jar:file:/C:/Users/Alan/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.5.17.RELEASE/spring-boot-autoconfigure-1.5.17.RELEASE.jar!/META-INF/spring.factories
該文件也有7個鍵值對,新生成的properties大小為7:
此時properties.getProperty(factoryClassName)將能找到key=org.springframework.boot.autoconfigure.EnableAutoConfiguration的屬性鍵值對。
factoryClassNames此時包含了org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的value值,最后全部添加到list集合里面,共有96個值(Arrays.asList轉換得到):
第三次遍歷jar:file:/C:/Users/Alan/.m2/repository/org/springframework/spring-beans/4.3.20.RELEASE/spring-beans-4.3.20.RELEASE.jar!/META-INF/spring.factories
但是里面仍然沒有org.springframework.boot.autoconfigure.EnableAutoConfiguration的key,所以result里面並沒有添加新元素。
總共進行了3次遍歷,分別是下面3個jar包包含spring.factories文件:
1、spring-boot-1.5.17.RELEASE.jar
2、spring-boot-autoconfigure-1.5.17.RELEASE.jar
3、spring-beans-4.3.20.RELEASE.jar
而上述3個jar的spring.factories只有spring-boot-autoconfigure-1.5.17.RELEASE.jar中包含org.springframework.boot.autoconfigure.EnableAutoConfiguration的key,這樣就把需要自動配置的候選類都找出並放入list集合中。
接着還會用斷言判斷configurations是否有元素,否則提示:No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.
最后返回自動配置類的list集合對象configurations。
第四處斷點:
filter方法傳入了2個參數:
1、configurations:讀取MEAT-INF/spring.factories文件得到的經過排除得到的自動配置類名的list集合
2、autoConfigurationMetadata:讀取META-INF/spring-autoconfigure-metadata.properties文件得到的485個鍵值對。
候選自動配置類數組candidates 由configurations轉數組而來:String[] candidates = configurations.toArray(new String[configurations.size()]);其值如下:
for循環中的getAutoConfigurationImportFilters定義如下:
里面的SpringFactoriesLoader.loadFactories()方法定義如下:
上述方法主要目的是找尋spring.factories文件中key=org.springframework.boot.autoconfigure.AutoConfigurationImportFilter對應的值,
這里依然進行了3次遍歷,分別是下面3個jar包包含spring.factories文件
1、spring-boot-1.5.17.RELEASE.jar
2、spring-boot-autoconfigure-1.5.17.RELEASE.jar
3、spring-beans-4.3.20.RELEASE.jar
而上述3個jar的spring.factories只有spring-boot-autoconfigure-1.5.17.RELEASE.jar中包含了org.springframework.boot.autoconfigure.AutoConfigurationImportFilter的key。
通過loadFactoryNames(factoryClass, classLoaderToUse)得到的factoryNames為org.springframework.boot.autoconfigure.condition.OnClassCondition類。
接着遍歷factoryNames,調用instantiateFactory方法,利用反射生成condition.OnClassCondition的實例添加到result集合中:
最后對result進行排序並返回:AnnotationAwareOrderComparator.sort(result);
getAutoConfigurationImportFilters()分析完了,我們繼續看for循環:
上面的invokeAwareMethods(filter)方法根據filter是否實現了相關接口,對其進行了設置:
filter滿足instance instanceof Aware、instance instanceof BeanClassLoaderAware、instance instanceof BeanFactoryAware。
接下來我們着重看下match方法:
上述方法調用了OnClassCondition類的match方法:
傳入的參數是之前排除過自動配置類,目前還有96個:
下面的方法利用autoConfigurationMetadata對象對autoConfigurationClasses進行處理,autoConfigurationMetadata是加載META-INF/spring-autoconfigure-metadata.properties得到的485個元素,autoConfigurationClasses是讀取META-INF/spring.factories文件key為org.springframework.boot.autoconfigure.EnableAutoConfiguration得到值進行排除、排序、去重等操作得到的候選自動配置類(由於沒有添加排除項,目前仍然有96個)。
getOutComes定義如下:
該方法將自動候選配置類分成2半進行條件判斷處理,outcomes存入的是條件判斷后的結果:
匹配結束后的ConditionEvaluationReport對象report存放了不匹配的結果,從結果中看到候選的96個自動配置類,有72個不滿足條件而被過濾:
隨便點開一個outcomes元素:
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration -> key=org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
匹配失敗原因:@ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice'
由於項目沒有引入Aop的相關依賴,導致類路徑中沒有Aspect和Advice類,因此AopAutoConfiguration這個自動配置類匹配失敗,無法進行自動配置。
(1) META-INF/spring-autoconfigure-metadata.properties文件中的Aop內容:
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.Configuration=
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration=
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration.ConditionalOnClass=
org.springframework.context.annotation.EnableAspectJAutoProxy,org.aspectj.lang.annotation.Aspect,org.aspectj.lang.reflect.Advice
(2) META-INF/spring.factories中的Aop內容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
因此spring.factories中的key=org.springframework.boot.autoconfigure.EnableAutoConfiguration對應的值只是候選的自動配置類;
能否成功配置,關鍵還要看是否已經被排除以及是否滿足spring-autoconfigure-metadata.properties中對對應配置類的加載條件。
若不滿足,則該類是會從自動配置類列表中排除,這樣能加快springboot的啟動速度。spring官方文檔(https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html)對該文件的作用描述如下:
Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file (META-INF/spring-autoconfigure-metadata.properties
). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time.
然后根據匹配結果,將真正滿足配置條件的配置類放入list集合中 boolean[] skip記錄了對應的候選自動配置類是否需要跳過,true-不滿足條件,需要跳過,false-滿足條件,不需要跳過。
for循環結束,只有24個自動配置真正符合條件:
因此第四處斷點走完,真正符合自動配置條件類的自動配置類只有24個了(根據項目配置情況會有所不同):
至此,SpringBoot自動配置源碼調試告一段落,總結如下:
1、讀取META-INF/spring-autoconfigure-metadata.properties文件中的內容;
2、獲取需要排除的自動配置類;
3、讀取spring-boot-autoconfigure-1.5.17.RELEASE.jar中的META-INF/spring.factories文件內容,作為候選自動配置類;
4、對候選自動配置類進行去重、排序、去除所有排除項;
5、利用META-INF/spring-autoconfigure-metadata.properties文件的配置對META-INF/spring.factories經歷第四步處理后的候選自動配置類進行過濾,去除不滿足加載條件的類,得到最終的自動配置類供SpringBoot加載。