SpringBoot自動(dòng)配置原理詳解_第1頁(yè)
SpringBoot自動(dòng)配置原理詳解_第2頁(yè)
SpringBoot自動(dòng)配置原理詳解_第3頁(yè)
SpringBoot自動(dòng)配置原理詳解_第4頁(yè)
SpringBoot自動(dòng)配置原理詳解_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第SpringBoot自動(dòng)配置原理詳解@SpringBootConfiguration(里面就是@Configuration,標(biāo)注當(dāng)前類(lèi)為配置類(lèi),其實(shí)只是做了一層封裝改了個(gè)名字而已)

@EnableAutoConfiguration(開(kāi)啟自動(dòng)配置)

@ComponentScan(包掃描)

注:@Inherited是一個(gè)標(biāo)識(shí),用來(lái)修飾注解,如果一個(gè)類(lèi)用上了@Inherited修飾的注解,那么其子類(lèi)也會(huì)繼承這個(gè)注解

我們下面逐一分析這3個(gè)注解作用

3.1.1@SpringBootConfiguration

我們繼續(xù)點(diǎn)@SpringBootConfiguration進(jìn)去查看源碼如下:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration

@Indexed

public@interfaceSpringBootConfiguration{

@AliasFor(

annotation=Configuration.class

booleanproxyBeanMethods()defaulttrue;

@Configuration標(biāo)注在某個(gè)類(lèi)上,表示這是一個(gè)springboot的配置類(lèi)。可以向容器中注入組件。

3.1.2@ComponentScan

@ComponentScan:配置用于Configuration類(lèi)的組件掃描指令。

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

可以basePackageClasses或basePackages來(lái)定義要掃描的特定包。如果沒(méi)有定義特定的包,將從聲明該注解的類(lèi)的包開(kāi)始掃描。

3.1.3@EnableAutoConfiguration

@EnableAutoConfiguration顧名思義就是:開(kāi)啟自動(dòng)導(dǎo)入配置

這個(gè)注解是SpringBoot的重點(diǎn),我們下面詳細(xì)講解

四、@EnableAutoConfiguration

我們點(diǎn)進(jìn)去看看該注解有什么內(nèi)容

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage//自動(dòng)導(dǎo)包

@Import({AutoConfigurationImportSelector.class})//自動(dòng)配置導(dǎo)入選擇

public@interfaceEnableAutoConfiguration{

StringENABLED_OVERRIDE_PROPERTY="spring.boot.enableautoconfiguration";

Class[]exclude()default{};

String[]excludeName()default{};

4.1@AutoConfigurationPackage

自動(dòng)導(dǎo)入配置包

點(diǎn)進(jìn)去查看代碼:

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import({Registrar.class})

public@interfaceAutoConfigurationPackage{

String[]basePackages()default{};

Class[]basePackageClasses()default{};

@Import為spring的注解,導(dǎo)入一個(gè)配置文件,在springboot中為給容器導(dǎo)入一個(gè)組件,而導(dǎo)入的組件由AutoConfigurationPackages.class的內(nèi)部類(lèi)Registrar.class執(zhí)行邏輯來(lái)決定是如何導(dǎo)入的。

4.1.1@Import({Registrar.class})

點(diǎn)Registrar.class進(jìn)去查看源碼如下:

staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{

Registrar(){

publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){

//斷點(diǎn)

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

publicSetObjectdetermineImports(AnnotationMetadatametadata){

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

注:Registrar實(shí)現(xiàn)了ImportBeanDefinitionRegistrar類(lèi),就可以被注解@Import導(dǎo)入到spring容器里。

這個(gè)地方打斷點(diǎn)

運(yùn)行可以查看到(String[])(newAutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(newString[0])的值為com.ljw.springbootwork:當(dāng)前啟動(dòng)類(lèi)所在的包名

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

4.2

@Import({AutoConfigurationImportSelector.class})

作用:AutoConfigurationImportSelector開(kāi)啟自動(dòng)配置類(lèi)的導(dǎo)包的選擇器,即是帶入哪些類(lèi),有選擇性的導(dǎo)入

點(diǎn)AutoConfigurationImportSelector.class進(jìn)入查看源碼,這個(gè)類(lèi)中有兩個(gè)方法見(jiàn)名知意:

1.selectImports:選擇需要導(dǎo)入的組件

publicString[]selectImports(AnnotationMetadataannotationMetadata){

if(!this.isEnabled(annotationMetadata)){

returnNO_IMPORTS;

}else{

AutoConfigurationImportSelector.AutoConfigurationEntryautoConfigurationEntry=this.getAutoConfigurationEntry(annotationMetadata);

returnStringUtils.toStringArray(autoConfigurationEntry.getConfigurations());

2.getAutoConfigurationEntry:根據(jù)導(dǎo)入的@Configuration類(lèi)的AnnotationMetadata返回AutoConfigurationImportSelector.AutoConfigurationEntry

protectedAutoConfigurationImportSelector.AutoConfigurationEntrygetAutoConfigurationEntry(AnnotationMetadataannotationMetadata){

if(!this.isEnabled(annotationMetadata)){

returnEMPTY_ENTRY;

}else{

AnnotationAttributesattributes=this.getAttributes(annotationMetadata);

//這打個(gè)斷點(diǎn),看看返回的數(shù)據(jù)

ListStringconfigurations=this.getCandidateConfigurations(annotationMetadata,attributes);

//刪除重復(fù)項(xiàng)

configurations=this.removeDuplicates(configurations);

SetStringexclusions=this.getExclusions(annotationMetadata,attributes);

//檢查

this.checkExcludedClasses(configurations,exclusions);

//刪除需要排除的依賴(lài)

configurations.removeAll(exclusions);

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

this.fireAutoConfigurationImportEvents(configurations,exclusions);

returnnewAutoConfigurationImportSelector.AutoConfigurationEntry(configurations,exclusions);

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

configurations數(shù)組長(zhǎng)度為133,并且文件后綴名都為**AutoConfiguration

結(jié)論:這些都是候選的配置類(lèi),經(jīng)過(guò)去重,去除需要的排除的依賴(lài),最終的組件才是這個(gè)環(huán)境需要的所有組件。有了自動(dòng)配置,就不需要我們自己手寫(xiě)配置的值了,配置類(lèi)有默認(rèn)值的。

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

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中沒(méi)有找到自動(dòng)配置類(lèi)。如果您使用自定義包裝,請(qǐng)確保該文件是正確的。“

結(jié)論:即是要loadFactoryNames()方法要找到自動(dòng)的配置類(lèi)返回才不會(huì)報(bào)錯(cuò)。

getSpringFactoriesLoaderFactoryClass()

我們點(diǎn)進(jìn)去發(fā)現(xiàn):this.getSpringFactoriesLoaderFactoryClass()返回的是EnableAutoConfiguration.class這個(gè)注解。這個(gè)注解和@SpringBootApplication下標(biāo)識(shí)注解是同一個(gè)注解。

protectedClassgetSpringFactoriesLoaderFactoryClass(){

returnEnableAutoConfiguration.class;

結(jié)論:獲取一個(gè)能加載自動(dòng)配置類(lèi)的類(lèi),即SpringBoot默認(rèn)自動(dòng)配置類(lèi)為EnableAutoConfiguration

4.2.2SpringFactoriesLoader

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

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

loadFactoryNames()

publicstaticListStringloadFactoryNames(ClassfactoryType,@NullableClassLoaderclassLoader){

ClassLoaderclassLoaderToUse=classLoader;

if(classLoaderToUse==null){

classLoaderToUse=SpringFactoriesLoader.class.getClassLoader();

StringfactoryTypeName=factoryType.getName();

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

斷點(diǎn)查看factoryTypeName:

先是將EnableAutoConfiguration.class傳給了factoryType

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

org.springframework.boot.autoconfigure.EnableAutoConfiguration

loadSpringFactories()

接著查看loadSpringFactories方法的作用

privatestaticMapString,ListStringloadSpringFactories(ClassLoaderclassLoader){

//斷點(diǎn)查看

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){

//斷點(diǎn)

puteIfAbsent(factoryTypeName,key-newArrayList())

.add(factoryImplementationName.trim());

//Replacealllistswithunmodifiablelistscontaininguniqueelements

//去重,斷點(diǎn)查看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包的當(dāng)前類(lèi)路徑下的META-INF/spring.factories文件都會(huì)被讀取,如:

斷點(diǎn)查看result值如下:

該方法作用是加載所有依賴(lài)的路徑META-INF/spring.factories文件,通過(guò)map結(jié)構(gòu)保存,key為文件中定義的一些標(biāo)識(shí)工廠類(lèi),value就是能自動(dòng)配置的一些工廠實(shí)現(xiàn)的類(lèi),value用list保存并去重。

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

因?yàn)閘oadFactoryNames方法攜帶過(guò)來(lái)的第一個(gè)參數(shù)為EnableAutoConfiguration.class,所以factoryType值也為EnableAutoConfiguration.class,那么factoryTypeName值為EnableAutoConfiguration。拿到的值就是META-INF/spring.factories文件下的key為

org.springframework.boot.autoconfigure.EnableAutoConfiguration的值

getOrDefault當(dāng)Map集合中有這個(gè)key時(shí),就使用這個(gè)key值,如果沒(méi)有就使用默認(rèn)值空數(shù)組

結(jié)論:

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

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

溫馨提示

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

評(píng)論

0/150

提交評(píng)論