SpringBoot示例分析講解自動化裝配機(jī)制核心注解_第1頁
SpringBoot示例分析講解自動化裝配機(jī)制核心注解_第2頁
SpringBoot示例分析講解自動化裝配機(jī)制核心注解_第3頁
SpringBoot示例分析講解自動化裝配機(jī)制核心注解_第4頁
SpringBoot示例分析講解自動化裝配機(jī)制核心注解_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第SpringBoot示例分析講解自動化裝配機(jī)制核心注解目錄1.自動化裝配介紹2.SpringBoot自動化配置UML圖解3.SpringBoot自動化配置核心注解分析3.1@Inherited3.2@SpringBootConfiguration3.3@EnableAutoConfiguration3.4@ComponentScan3.5@ConfigurationPropertiesScan3.6@AutoConfigurationImportSelector3.7@AutoConfigurationPackages4.總結(jié)

1.自動化裝配介紹

SpringBoot針對mvc做了大量封裝,簡化開發(fā)者的使用,內(nèi)部是如何管理資源配置,Bean配置,環(huán)境變量配置以及啟動配置等?實(shí)質(zhì)是SpringBoot做了大量的注解封裝,比如@SpringBootApplication,同時(shí)采用Spring4框架的新特性@Conditional基于條件的Bean創(chuàng)建管理機(jī)制來實(shí)現(xiàn);

實(shí)際的工作場景中是復(fù)雜多樣的,有些項(xiàng)目需要不同的組件,比如REDIS、MONGODB作緩存;RABBITMQ、KAFKA作消息隊(duì)列;有些項(xiàng)目運(yùn)行環(huán)境不同,比如JDK7、JDK8不同版本,面對眾多復(fù)雜的需求,又要做到最大化支持,SpringBoot是如何管理實(shí)現(xiàn)的,這就依賴Conditional功能,基于條件的自動化配置。

2.SpringBoot自動化配置UML圖解

SpringBootApplication是我們所常用熟知的注解,它是一個組合注解,依賴多個注解,共同實(shí)現(xiàn)SpringBoot應(yīng)用功能,以下為所有依賴的UML圖解,我們圍繞這些注解深入研究,看下具體的實(shí)現(xiàn)。

3.SpringBoot自動化配置核心注解分析

SpringBootApplication注解:

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@SpringBootConfiguration

@EnableAutoConfiguration

@ComponentScan(excludeFilters={@Filter(type=FilterType.CUSTOM,classes=TypeExcludeFilter.class),

@Filter(type=FilterType.CUSTOM,classes=AutoConfigurationExcludeFilter.class)})

@ConfigurationPropertiesScan

public@interfaceSpringBootApplication{

*需要排除的自動化配置,根據(jù)類名進(jìn)行排除,比如MongoAutoConfiguration,JpaRepositoriesAutoConfiguration等

@AliasFor(annotation=EnableAutoConfiguration.class)

Class[]exclude()default{};

*需要排除的自動化配置,根據(jù)名稱進(jìn)行排除

@AliasFor(annotation=EnableAutoConfiguration.class)

String[]excludeName()default{};

*指定需要掃描的包路徑,參數(shù)填寫包名

@AliasFor(annotation=ComponentScan.class,attribute="basePackages")

String[]scanBasePackages()default{};

*指定需要掃描的包路徑

@AliasFor(annotation=ComponentScan.class,attribute="basePackageClasses")

Class[]scanBasePackageClasses()default{};

*Bean方法的動態(tài)代理配置,如果沒有采用工廠方法,可以標(biāo)記為false,采用cglib代理。

@AliasFor(annotation=Configuration.class)

booleanproxyBeanMethods()defaulttrue;

}

3.1@Inherited

java.lang.annotation.@Inherited注解,從包名可以看出為JDK自帶注解,作用是讓子類能夠繼承父類中引用Inherited的注解,但需注意的是,該注解作用范圍只在類聲明中有效;如果是接口與接口的繼承,類與接口的繼承,是不會生效。

3.2@SpringBootConfiguration

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration(proxyBeanMethods=false)

public@interfaceSpringBootConfiguration{

*Bean方法的動態(tài)代理配置

@AliasFor(annotation=Configuration.class)

booleanproxyBeanMethods()defaulttrue;

}

這是配置型處理注解,可以看到內(nèi)部源碼引用了@Configuration注解,

自身沒有太多的實(shí)現(xiàn),那為什么還需要再包裝?官方給出的解釋是對Spring的@Configuration的擴(kuò)展,

用于實(shí)現(xiàn)SpringBoot的自動化配置。proxyBeanMethods屬性默認(rèn)為true,作用是對bean的方法是否開啟代理方式調(diào)用,默認(rèn)為true,如果沒有采用工廠方法,可以設(shè)為false,通過cglib作動態(tài)代理。

3.3@EnableAutoConfiguration

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

public@interfaceEnableAutoConfiguration{

//設(shè)置注解支持重載的標(biāo)識

StringENABLED_OVERRIDE_PROPERTY="spring.boot.enableautoconfiguration";

*排除自動化配置的組件,如MongoAutoConfiguration,JpaRepositoriesAutoConfiguration等

Class[]exclude()default{};

*排除自動化配置的組件,根據(jù)名稱設(shè)置

String[]excludeName()default{};

}

用于管理開啟SpringBoot的各種自動化配置注解,如datasource,mongodb,redis等,也是spring-boot-autoconfigure工程的核心注解。

AutoConfigurationPackage

它的主要作用是掃描主程序同級及下級的包路徑所有Bean與組件注冊到SpringIoc容器中。

Import

它可以把沒有聲明配置的類注冊到SpringIoc容器中管理引用。導(dǎo)入的AutoConfigurationImportSelector類實(shí)現(xiàn)BeanClassLoaderAware、ResourceLoaderAware、EnvironmentAware等接口,管理類裝載器,資源裝載器及環(huán)境配置等,是一個負(fù)責(zé)處理自動化配置導(dǎo)入的選擇管理器。在下面【@AutoConfigurationImportSelector剖析】進(jìn)行詳解。

3.4@ComponentScan

這是我們在Spring下面常用的一個注解,它可以掃描Spring定義的注解,如@Componment,@Service等,常用的屬性有basePackages掃描路徑,includeFilters包含路徑過濾器,excludeFilters排除路徑過濾器,lazyInit是否懶加載等,能夠非常靈活的掃描管理需要注冊組件。

3.5@ConfigurationPropertiesScan

作用是掃描指定包及子包路徑下面的ConfigurationProperties注解,管理工程配置屬性信息。主要屬性為basePackages掃描路徑,支持多個路徑,數(shù)組形式;basePackageClasses屬性也可以具體到包下面的類,

支持多個配置。

3.6@AutoConfigurationImportSelector

AutoConfigurationImportSelector實(shí)現(xiàn)DeferredImportSelector、BeanClassLoaderAware、ResourceLoaderAware、BeanFactoryAware、EnvironmentAware、Ordered接口,為自動化配置的核心處理類,主要負(fù)責(zé)自動化配置規(guī)則的一系列處理邏輯:

/**

*{@linkDeferredImportSelector}tohandle{@linkEnableAutoConfiguration

*auto-configuration}.Thisclasscanalsobesubclassedifacustomvariantof

*{@linkEnableAutoConfiguration@EnableAutoConfiguration}isneeded.

*@authorPhillipWebb

*@authorAndyWilkinson

*@authorStephaneNicoll

*@authorMadhuraBhave

*@since1.3.0

*@seeEnableAutoConfiguration

publicclassAutoConfigurationImportSelectorimplementsDeferredImportSelector,BeanClassLoaderAware,

ResourceLoaderAware,BeanFactoryAware,EnvironmentAware,Ordered{

}

講解幾個技術(shù)點(diǎn):

getCandidateConfigurations方法

protectedListStringgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){

ListStringconfigurations=SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),

getBeanClassLoader());

Assert.notEmpty(configurations,"NoautoconfigurationclassesfoundinMETA-INF/spring.factories.Ifyou"

+"areusingacustompackaging,makesurethatfileiscorrect.");

returnconfigurations;

}

該方法是獲取所有SpringBoot聲明定義的自動化配置類。

看下具體有哪些信息:

這些實(shí)際是配置在Spring-boot-autoconfigure工程下的META-INF/spring.factories文件中:

看到這里,我們應(yīng)該可以明白,為什么AOP,RABBIT,DATASOURCE,REIDS等組件SPRINGBOOT都能幫我們快速配置實(shí)現(xiàn),其實(shí)它內(nèi)部遵循SPI機(jī)制,已經(jīng)把自動化配置做好了封裝。

AutoConfigurationGroup類

它是AutoConfigurationImportSelector的內(nèi)部類,實(shí)現(xiàn)了DeferredImportSelector.Group、BeanClassLoaderAware、BeanFactoryAware、ResourceLoaderAware接口,是一個重要的核心類。主要作用是負(fù)責(zé)自動化配置條目信息的記錄,排序,元數(shù)據(jù)處理等。它通過getImportGroup方法獲取返回,該方法實(shí)現(xiàn)DeferredImportSelector的接口。

privatestaticclassAutoConfigurationGroup

implementsDeferredImportSelector.Group,BeanClassLoaderAware,BeanFactoryAware,ResourceLoaderAware{

//記錄注解的元數(shù)據(jù)

privatefinalMapString,AnnotationMetadataentries=newLinkedHashMap();

//記錄自動化配置條目,放入集合

privatefinalListAutoConfigurationEntryautoConfigurationEntries=newArrayList();

//設(shè)置bean的類加載器

privateClassLoaderbeanClassLoader;

//設(shè)置bean工廠信息

privateBeanFactorybeanFactory;

//設(shè)置資源加載器信息

privateResourceLoaderresourceLoader;

//設(shè)置自動化配置的元數(shù)據(jù)記錄

privateAutoConfigurationMetadataautoConfigurationMetadata;

}

屬性主要定義了一些自動化配置類目信息、BEAN工廠、類和資源加載器信息。entries條目有22條,具體內(nèi)容如下:

里面是主要的自動化配置類的元數(shù)據(jù)信息,autoConfigurationEntries屬性就是具體的自動化配置條目。這些主要自動化類配置是Springboot幫助我們實(shí)現(xiàn)mvc的核心功能,如請求分發(fā),文件上傳,參數(shù)驗(yàn)證,編碼轉(zhuǎn)換等功能。還有一部分是定制條件自動化配置類,

autoConfigurationMetadata元數(shù)據(jù)內(nèi)容較多,包含各種組件,根據(jù)環(huán)境配置和版本不同,這里可以看到共有705個:

由于SpringBoot支持眾多插件,功能豐富,數(shù)量較多;這里存在些疑問,這里面的元數(shù)據(jù)和上面的entries條目都是AutoConfiguration自動化配置類,那有什么區(qū)別?其實(shí)這里面的,都是基于條件的自動化配置。

我們就拿KafkaAutoConfiguration來看:

可以看到注解ConditionalOnClass,意思是KafkaAutoConfiguration生效的前提是基于KafkaTemplate類的初始化成功,這就是定制條件,也就是基于條件的自動化配置類,雖然有七百多個,但其實(shí)是根據(jù)工程實(shí)際用到的組件,才會觸發(fā)加載對應(yīng)的配置。有關(guān)Conditional基于條件的自動化配置實(shí)現(xiàn)原理,在下面我們再作深入研究。

繼續(xù)看AutoConfigurationImportSelector內(nèi)部類的selectImports方法:

@Override

publicIterableEntryselectImports(){

if(this.autoConfigurationEntries.isEmpty()){

returnCollections.emptyList();

//將所有自動化條目根據(jù)配置的Exclusion條件作過濾,并轉(zhuǎn)換為SET集合

SetStringallExclusions=this.autoConfigurationEntries.stream()

.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());

//SET集合,記錄所有需要處理的自動化配置

SetStringprocessedConfigurations=this.autoConfigurationEntries.stream()

.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)

.collect(Collectors.toCollection(LinkedHashSet::new));

//兩個SET,做交集過濾,排除不需要的配置

processedConfigurations.removeAll(allExclusions);

//最后進(jìn)行排序處理

returnsortAutoConfigurations(processedConfigurations,getAutoConfigurationMetadata()).stream()

.map((importClassName)-newEntry(this.entries.get(importClassName),importClassName))

.collect(Collectors.toList());

}

該方法是針對autoConfigurationEntries自動化配置條目做過濾,根據(jù)指定的排除規(guī)則處理;再根據(jù)設(shè)置的啟動的優(yōu)先級做排序整理。從代碼中可以看到,先獲取所有的allExclusions排除配置信息,再獲取所有需要處理的processedConfigurations配置信息,然后做過濾處理,最后再調(diào)用sortAutoConfigurations方法,根據(jù)order順序做排序整理。

AutoConfigurationImportSelector內(nèi)部類的process方法:

@Override

publicvoidprocess(AnnotationMetadataannotationMetadata,DeferredImportSelectordeferredImportSelector){

Assert.state(deferredImportSelectorinstanceofAutoConfigurationImportSelector,

()-String.format("Only%simplementationsaresupported,got%s",

AutoConfigurationImportSelector.class.getSimpleName(),

deferredImportSelector.getClass().getName()));

//獲取自動化配置條目

AutoConfigurationEntryautoConfigurationEntry=((AutoConfigurationImportSelector)deferredImportSelector)

.getAutoConfigurationEntry(getAutoConfigurationMetadata(),annotationMetadata);

//記錄獲取的條目

this.autoConfigurationEntries.add(autoConfigurationEntry);

for(StringimportClassName:autoConfigurationEntry.getConfigurations()){

//放入成員變量entries中

this.entries.putIfAbsent(importClassName,annotationMetadata);

}

該方法是掃描獲取autoConfigurationEntries自動化配置條目信息。

annotationMetadata參數(shù):

為注解元數(shù)據(jù),有也就是被@SpringBootApplication修飾的類信息,在這里就是我們的啟動入口類信息。

deferredImportSelector參數(shù):

通過@EnableAutoConfiguration注解定義的@Import的類,也就是AutoConfigurationImportSelector對象。根據(jù)配置,會加載指定的beanFactory、classLoader、resourceLoader和environment對象。

AutoConfigurationImportSelector內(nèi)部類的getAutoConfigurationEntry方法:

protectedAutoConfigurationEntrygetAutoConfigurationEntry(AutoConfigurationMetadataautoConfigurationMetadata,

AnnotationMetadataannotationMetadata){

//1、判斷是否開對應(yīng)注解

if(!isEnabled(annotationMetadata)){

returnEMPTY_ENTRY;

//2、獲取注解定義的屬性

AnnotationAttributesattributes=getAttributes(annotationMetadata);

//3、獲取符合規(guī)則的SpringBoot內(nèi)置的自動化配置類,并做去重處理

ListStringconfigurations=getCandidateConfigurations(annotationMetadata,attributes);

configurations=removeDuplicates(configurations);

//4、做排除規(guī)則匹配,過濾處理

SetStringexclusions=getExclusions(annotationMetadata,attributes);

checkExcludedClasses(configurations,exclusions);

configurations.removeAll(exclusions);

configurations=filter(configurations,autoConfigurationMetadata);

//5、觸發(fā)自動導(dǎo)入處理完成事件

fireAutoConfigurationImportEvents(configurations,exclusions);

returnnewAutoConfigurationEntry(configurations,exclusions);

}

該方法主要作用是獲取SpringBoot內(nèi)置的自動化條目,例AopAutoConfiguration等,該方法會調(diào)用上面講解的getCandidateConfigurations方法。主要步驟邏輯如下:

判斷是否開啟元注解掃描,對應(yīng)屬性為spring.boot.enableautoconfiguration,默認(rèn)情況下,是開啟自動配置。獲取定義的注解屬性,跟蹤內(nèi)部源碼,里面會返回exclude和excludeName等屬性。獲取符合規(guī)則的SpringBoot內(nèi)置的自動化配置,并做去重處理,也就是我們上面講解的getCandidateConfigurations方法,從中我們就可以理解其中的關(guān)聯(lián)關(guān)系。做排除規(guī)則檢查與過濾處理,根據(jù)上面第2個步驟獲取的exclude等屬性以及配置屬性spring.autoconfigure.exclude做過濾處理。觸發(fā)自動導(dǎo)入完成事件,該方法內(nèi)部邏輯正常處理完成才會觸發(fā),會調(diào)用AutoConfigurationImportListener監(jiān)聽器做通知處理。

3.7@AutoConfigurationPackages

AutoConfigurationPackages是EnableAutoConfiguration上的另一個核心注解類,官方解釋為:

Indicatesthatthepackagecontainingtheannotatedclassshouldberegistered

意思是包含該注解的類,所在包下面的class,都會注冊到SpringIoc容器中。對應(yīng)源碼:

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import(AutoConfigurationPackages.Registrar.class)

public@interfaceAutoConfigurationPackage{

Import注解,導(dǎo)入AutoConfigurationPackages抽象類下面的內(nèi)部靜態(tài)類Registrar,研究Registrar實(shí)現(xiàn)原理:

Registrar實(shí)現(xiàn)ImportBeanDefinitionRegistrar、DeterminableImports接口,它負(fù)責(zé)存儲從@AutoConfigurationPackage注解掃描到的信息。源碼如下:

staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{

//注冊BEAN的定義信息

@Override

publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){

register(registry,newPackageImport(metadata).getPackageName());

//決定是否導(dǎo)入注解中的配置內(nèi)容

@Override

publicSetObjectdetermineImports(AnnotationMetadatametadata){

returnCollections.singleton(newPackageImport(metadata));

}

這里面主要涉及到PackageImport類,它是AutoConfigurationPackages的內(nèi)部私有靜態(tài)類,主要是記錄導(dǎo)入的報(bào)名信息,源碼如下:

/**

*Wrapperforapackageimport.

privatestaticfinalclassPackageImport{

privatefinalStringpackageName;

//構(gòu)造方法,記錄注解內(nèi)容

PackageImport(AnnotationMetadatametadata){

this.packageName=ClassUtils.getPackageName(metadata.getClassName());

//獲取指定包名稱

publicStringgetPackageName(){

returnthis.packageName;

//重載父類比較邏輯,根據(jù)包名判斷

@Override

publicbooleanequals(Objectobj){

if(obj==null||getClass()!=obj.getClass()){

returnfalse;

returnthis.packageName.equals(((PackageImport)obj).packageName);

//重載hash標(biāo)識,以包名的HASH值為準(zhǔn)

@Override

publicinthashCode(){

returnthis.packageName.hashCode();

//重載toString,打印內(nèi)容

@Override

publicStringtoString(){

return"PackageImport"+this.packageName;

}

內(nèi)部斷點(diǎn)跟蹤的話,可以看到它記錄的是我們啟動類所在的包名。這也就是為什么不需要指定掃描包路徑,也會加載啟動類所在包下面的JavaConfig配置信息。

回到上面Registrar的registerBeanDefinitions方法,內(nèi)部調(diào)用的是register方法:

它是處理記錄AutoConfigurationPackages掃描包信息,源碼如下:

publicstaticvoidregister(BeanDefinitionRegistryregistry,String...packageNames){

//判斷是否包含BEAN定義信息,如果包含,更新packageNames信息

if(registry.containsBeanDefinition(BEAN)){

BeanDefinitionbeanDefinition=registry.getBeanDefinition(BEAN);

ConstructorArgumentValuesconstructorArguments=beanDefinition.getConstructorArgumentValues();

constructorArguments.addIndexedArgumentValue(0,addBasePackages(constructorArguments,packageNames));

//如果registry中

溫馨提示

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

評論

0/150

提交評論