SpringBoot自動配置原理詳解_第1頁
SpringBoot自動配置原理詳解_第2頁
SpringBoot自動配置原理詳解_第3頁
SpringBoot自動配置原理詳解_第4頁
SpringBoot自動配置原理詳解_第5頁
已閱讀5頁,還剩9頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第SpringBoot自動配置原理詳解@SpringBootConfiguration(里面就是@Configuration,標注當前類為配置類,其實只是做了一層封裝改了個名字而已)

@EnableAutoConfiguration(開啟自動配置)

@ComponentScan(包掃描)

注:@Inherited是一個標識,用來修飾注解,如果一個類用上了@Inherited修飾的注解,那么其子類也會繼承這個注解

我們下面逐一分析這3個注解作用

3.1.1@SpringBootConfiguration

我們繼續點@SpringBootConfiguration進去查看源碼如下:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration

@Indexed

public@interfaceSpringBootConfiguration{

@AliasFor(

annotation=Configuration.class

booleanproxyBeanMethods()defaulttrue;

@Configuration標注在某個類上,表示這是一個springboot的配置類。可以向容器中注入組件。

3.1.2@ComponentScan

@ComponentScan:配置用于Configuration類的組件掃描指令。

提供與SpringXML的context:component-scan元素并行的支持。

可以basePackageClasses或basePackages來定義要掃描的特定包。如果沒有定義特定的包,將從聲明該注解的類的包開始掃描。

3.1.3@EnableAutoConfiguration

@EnableAutoConfiguration顧名思義就是:開啟自動導入配置

這個注解是SpringBoot的重點,我們下面詳細講解

四、@EnableAutoConfiguration

我們點進去看看該注解有什么內容

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage//自動導包

@Import({AutoConfigurationImportSelector.class})//自動配置導入選擇

public@interfaceEnableAutoConfiguration{

StringENABLED_OVERRIDE_PROPERTY="spring.boot.enableautoconfiguration";

Class[]exclude()default{};

String[]excludeName()default{};

4.1@AutoConfigurationPackage

自動導入配置包

點進去查看代碼:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import({Registrar.class})

public@interfaceAutoConfigurationPackage{

String[]basePackages()default{};

Class[]basePackageClasses()default{};

@Import為spring的注解,導入一個配置文件,在springboot中為給容器導入一個組件,而導入的組件由AutoConfigurationPackages.class的內部類Registrar.class執行邏輯來決定是如何導入的。

4.1.1@Import({Registrar.class})

點Registrar.class進去查看源碼如下:

staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{

Registrar(){

publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){

//斷點

AutoConfigurationPackages.register(registry,(String[])(newAutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(newString[0]));

publicSetObjectdetermineImports(AnnotationMetadatametadata){

returnCollections.singleton(newAutoConfigurationPackages.PackageImports(metadata));

注:Registrar實現了ImportBeanDefinitionRegistrar類,就可以被注解@Import導入到spring容器里。

這個地方打斷點

運行可以查看到(String[])(newAutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(newString[0])的值為com.ljw.springbootwork:當前啟動類所在的包名

結論:@AutoConfigurationPackage就是將主配置類(@SpringBootApplication標注的類)所在的包下面所有的組件都掃描注冊到spring容器中。

4.2

@Import({AutoConfigurationImportSelector.class})

作用:AutoConfigurationImportSelector開啟自動配置類的導包的選擇器,即是帶入哪些類,有選擇性的導入

點AutoConfigurationImportSelector.class進入查看源碼,這個類中有兩個方法見名知意:

1.selectImports:選擇需要導入的組件

publicString[]selectImports(AnnotationMetadataannotationMetadata){

if(!this.isEnabled(annotationMetadata)){

returnNO_IMPORTS;

}else{

AutoConfigurationImportSelector.AutoConfigurationEntryautoConfigurationEntry=this.getAutoConfigurationEntry(annotationMetadata);

returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

2.getAutoConfigurationEntry:根據導入的@Configuration類的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry

protectedAutoConfigurationImportSelector.AutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadataannotationMetadata){

if(!this.isEnabled(annotationMetadata)){

returnEMPTY_ENTRY;

}else{

AnnotationAttributesattributes=this.getAttributes(annotationMetadata);

//這打個斷點,看看返回的數據

ListStringconfigurations=this.getCandidateConfigurations(annotationMetadata,attributes);

//刪除重復項

configurations=this.removeDuplicates(configurations);

SetStringexclusions=this.getExclusions(annotationMetadata,attributes);

//檢查

this.checkExcludedClasses(configurations,exclusions);

//刪除需要排除的依賴

configurations.removeAll(exclusions);

configurations=this.getConfigurationClassFilter().filter(configurations);

this.fireAutoConfigurationImportEvents(configurations,exclusions);

returnnewAutoConfigurationImportSelector.AutoConfigurationEntry(configurations,exclusions);

this.getCandidateConfigurations(annotationMetadata,attributes)這里斷點查看

configurations數組長度為133,并且文件后綴名都為**AutoConfiguration

結論:這些都是候選的配置類,經過去重,去除需要的排除的依賴,最終的組件才是這個環境需要的所有組件。有了自動配置,就不需要我們自己手寫配置的值了,配置類有默認值的。

我們繼續往下看看是如何返回需要配置的組件的

4.2.1getCandidateConfigurations(annotationMetadata,attributes)

方法如下:

protectedListStringgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){

ListStringconfigurations=SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(),this.getBeanClassLoader());

Assert.notEmpty(configurations,"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyouareusingacustompackaging,makesurethatfileiscorrect.");

returnconfigurations;

這里有句斷言:Assert.notEmpty(configurations,"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyouareusingacustompackaging,makesurethatfileiscorrect.");

意思是:“在META-INF/spring.factories中沒有找到自動配置類。如果您使用自定義包裝,請確保該文件是正確的?!?/p>

結論:即是要loadFactoryNames()方法要找到自動的配置類返回才不會報錯。

getSpringFactoriesLoaderFactoryClass()

我們點進去發現:this.getSpringFactoriesLoaderFactoryClass()返回的是EnableAutoConfiguration.class這個注解。這個注解和@SpringBootApplication下標識注解是同一個注解。

protectedClassgetSpringFactoriesLoaderFactoryClass(){

returnEnableAutoConfiguration.class;

結論:獲取一個能加載自動配置類的類,即SpringBoot默認自動配置類為EnableAutoConfiguration

4.2.2SpringFactoriesLoader

SpringFactoriesLoader工廠加載機制是Spring內部提供的一個約定俗成的加載方式,只需要在模塊的META-INF/spring.factories文件,這個Properties格式的文件中的key是接口、注解、或抽象類的全名,value是以逗號“,“分隔的實現類,使用SpringFactoriesLoader來實現相應的實現類注入Spirng容器中。

注:會加載所有jar包下的classpath路徑下的META-INF/spring.factories文件,這樣文件不止一個。

loadFactoryNames()

publicstaticListStringloadFactoryNames(ClassfactoryType,@NullableClassLoaderclassLoader){

ClassLoaderclassLoaderToUse=classLoader;

if(classLoaderToUse==null){

classLoaderToUse=SpringFactoriesLoader.class.getClassLoader();

StringfactoryTypeName=factoryType.getName();

returnloadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());

斷點查看factoryTypeName:

先是將EnableAutoConfiguration.class傳給了factoryType

然后StringfactoryTypeName=factoryType.getName();,所以factoryTypeName值為

org.springframework.boot.autoconfigure.EnableAutoConfiguration

loadSpringFactories()

接著查看loadSpringFactories方法的作用

privatestaticMapString,ListStringloadSpringFactories(ClassLoaderclassLoader){

//斷點查看

MapString,ListStringresult=cache.get(classLoader);

if(result!=null){

returnresult;

result=newHashMap();

try{

//注意這里:META-INF/spring.factories

EnumerationURLurls=classLoader.getResources(FACTORIES_RESOURCE_LOCATION);

while(urls.hasMoreElements()){

URLurl=urls.nextElement();

UrlResourceresource=newUrlResource(url);

Propertiesproperties=PropertiesLoaderUtils.loadProperties(resource);

for(Map.Entry,entry:properties.entrySet()){

StringfactoryTypeName=((String)entry.getKey()).trim();

String[]factoryImplementationNames=

StringUmaDelimitedListToStringArray((String)entry.getValue());

for(StringfactoryImplementationName:factoryImplementationNames){

//斷點

puteIfAbsent(factoryTypeName,key-newArrayList())

.add(factoryImplementationName.trim());

//Replacealllistswithunmodifiablelistscontaininguniqueelements

//去重,斷點查看result值

result.replaceAll((factoryType,implementations)-implementations.stream().distinct()

.collect(Collectors.collectingAndThen(Collectors.toList(),Collections::unmodifiableList)));

cache.put(classLoader,result);

catch(IOExceptionex){

thrownewIllegalArgumentException("Unabletoloadfactoriesfromlocation["+

FACTORIES_RESOURCE_LOCATION+"]",ex);

returnresult;

這里的FACTORIES_RESOURCE_LOCATION在上面有定義:META-INF/spring.factories

publicfinalclassSpringFactoriesLoader{

*Thelocationtolookforfactories.

*pCanbepresentinmultipleJARfiles.

publicstaticfinalStringFACTORIES_RESOURCE_LOCATION="META-INF/spring.factories";

META-INF/spring.factories文件在哪里??

在所有引入的java包的當前類路徑下的META-INF/spring.factories文件都會被讀取,如:

斷點查看result值如下:

該方法作用是加載所有依賴的路徑META-INF/spring.factories文件,通過map結構保存,key為文件中定義的一些標識工廠類,value就是能自動配置的一些工廠實現的類,value用list保存并去重。

在回看loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());

因為loadFactoryNames方法攜帶過來的第一個參數為EnableAutoConfiguration.class,所以factoryType值也為EnableAutoConfiguration.class,那么factoryTypeName值為EnableAutoConfiguration。拿到的值就是META-INF/spring.factories文件下的key為

org.springframework.boot.autoconfigure.EnableAutoConfiguration的值

getOrDefault當Map集合中有這個key時,就使用這個key值,如果沒有就使用默認值空數組

結論:

loadSpringFactories()該方法就是從“META-INF/spring.factories”中加載給定類型的工廠實現的完全限定類名放到map中

loadFactoryNames()是根據SpringBoot的啟動生命流程,當需要加載自動配置類時,就會傳入org.springframework.boot.autoconfigure.EnableAutoConfiguration參數,從map中查找key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的值,這些值通過反射加到容器中,之后的作用就是用它們來做自動配置,這就是Sp

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論