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

下載本文檔

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

文檔簡(jiǎn)介

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

1.自動(dòng)化裝配介紹

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

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

2.SpringBoot自動(dòng)化配置UML圖解

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

3.SpringBoot自動(dòng)化配置核心注解分析

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{

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

@AliasFor(annotation=EnableAutoConfiguration.class)

Class[]exclude()default{};

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

@AliasFor(annotation=EnableAutoConfiguration.class)

String[]excludeName()default{};

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

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

String[]scanBasePackages()default{};

*指定需要掃描的包路徑

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

Class[]scanBasePackageClasses()default{};

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

@AliasFor(annotation=Configuration.class)

booleanproxyBeanMethods()defaulttrue;

}

3.1@Inherited

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

3.2@SpringBootConfiguration

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration(proxyBeanMethods=false)

public@interfaceSpringBootConfiguration{

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

@AliasFor(annotation=Configuration.class)

booleanproxyBeanMethods()defaulttrue;

}

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

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

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

3.3@EnableAutoConfiguration

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@AutoConfigurationPackage

@Import(AutoConfigurationImportSelector.class)

public@interfaceEnableAutoConfiguration{

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

StringENABLED_OVERRIDE_PROPERTY="spring.boot.enableautoconfiguration";

*排除自動(dòng)化配置的組件,如MongoAutoConfiguration,JpaRepositoriesAutoConfiguration等

Class[]exclude()default{};

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

String[]excludeName()default{};

}

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

AutoConfigurationPackage

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

Import

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

3.4@ComponentScan

這是我們?cè)赟pring下面常用的一個(gè)注解,它可以?huà)呙鑃pring定義的注解,如@Componment,@Service等,常用的屬性有basePackages掃描路徑,includeFilters包含路徑過(guò)濾器,excludeFilters排除路徑過(guò)濾器,lazyInit是否懶加載等,能夠非常靈活的掃描管理需要注冊(cè)組件。

3.5@ConfigurationPropertiesScan

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

支持多個(gè)配置。

3.6@AutoConfigurationImportSelector

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

/**

*{@linkDeferredImportSelector}tohandle{@linkEnableAutoConfiguration

*auto-configuration}.Thisclasscanalsobesubclassedifacustomvariantof

*{@linkEnableAutoConfiguration@EnableAutoConfiguration}isneeded.

*@authorPhillipWebb

*@authorAndyWilkinson

*@authorStephaneNicoll

*@authorMadhuraBhave

*@since1.3.0

*@seeEnableAutoConfiguration

publicclassAutoConfigurationImportSelectorimplementsDeferredImportSelector,BeanClassLoaderAware,

ResourceLoaderAware,BeanFactoryAware,EnvironmentAware,Ordered{

}

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

getCandidateConfigurations方法

protectedListStringgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){

ListStringconfigurations=SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),

getBeanClassLoader());

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

+"areusingacustompackaging,makesurethatfileiscorrect.");

returnconfigurations;

}

該方法是獲取所有SpringBoot聲明定義的自動(dòng)化配置類(lèi)。

看下具體有哪些信息:

這些實(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)把自動(dòng)化配置做好了封裝。

AutoConfigurationGroup類(lèi)

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

privatestaticclassAutoConfigurationGroup

implementsDeferredImportSelector.Group,BeanClassLoaderAware,BeanFactoryAware,ResourceLoaderAware{

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

privatefinalMapString,AnnotationMetadataentries=newLinkedHashMap();

//記錄自動(dòng)化配置條目,放入集合

privatefinalListAutoConfigurationEntryautoConfigurationEntries=newArrayList();

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

privateClassLoaderbeanClassLoader;

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

privateBeanFactorybeanFactory;

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

privateResourceLoaderresourceLoader;

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

privateAutoConfigurationMetadataautoConfigurationMetadata;

}

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

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

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

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

我們就拿KafkaAutoConfiguration來(lái)看:

可以看到注解ConditionalOnClass,意思是KafkaAutoConfiguration生效的前提是基于KafkaTemplate類(lèi)的初始化成功,這就是定制條件,也就是基于條件的自動(dòng)化配置類(lèi),雖然有七百多個(gè),但其實(shí)是根據(jù)工程實(shí)際用到的組件,才會(huì)觸發(fā)加載對(duì)應(yīng)的配置。有關(guān)Conditional基于條件的自動(dòng)化配置實(shí)現(xiàn)原理,在下面我們?cè)僮魃钊胙芯俊?/p>

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

@Override

publicIterableEntryselectImports(){

if(this.autoConfigurationEntries.isEmpty()){

returnCollections.emptyList();

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

SetStringallExclusions=this.autoConfigurationEntries.stream()

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

//SET集合,記錄所有需要處理的自動(dòng)化配置

SetStringprocessedConfigurations=this.autoConfigurationEntries.stream()

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

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

//兩個(gè)SET,做交集過(guò)濾,排除不需要的配置

processedConfigurations.removeAll(allExclusions);

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

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

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

.collect(Collectors.toList());

}

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

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

@Override

publicvoidprocess(AnnotationMetadataannotationMetadata,DeferredImportSelectordeferredImportSelector){

Assert.state(deferredImportSelectorinstanceofAutoConfigurationImportSelector,

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

AutoConfigurationImportSelector.class.getSimpleName(),

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

//獲取自動(dòng)化配置條目

AutoConfigurationEntryautoConfigurationEntry=((AutoConfigurationImportSelector)deferredImportSelector)

.getAutoConfigurationEntry(getAutoConfigurationMetadata(),annotationMetadata);

//記錄獲取的條目

this.autoConfigurationEntries.add(autoConfigurationEntry);

for(StringimportClassName:autoConfigurationEntry.getConfigurations()){

//放入成員變量entries中

this.entries.putIfAbsent(importClassName,annotationMetadata);

}

該方法是掃描獲取autoConfigurationEntries自動(dòng)化配置條目信息。

annotationMetadata參數(shù):

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

deferredImportSelector參數(shù):

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

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

protectedAutoConfigurationEntrygetAutoConfigurationEntry(AutoConfigurationMetadataautoConfigurationMetadata,

AnnotationMetadataannotationMetadata){

//1、判斷是否開(kāi)對(duì)應(yīng)注解

if(!isEnabled(annotationMetadata)){

returnEMPTY_ENTRY;

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

AnnotationAttributesattributes=getAttributes(annotationMetadata);

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

ListStringconfigurations=getCandidateConfigurations(annotationMetadata,attributes);

configurations=removeDuplicates(configurations);

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

SetStringexclusions=getExclusions(annotationMetadata,attributes);

checkExcludedClasses(configurations,exclusions);

configurations.removeAll(exclusions);

configurations=filter(configurations,autoConfigurationMetadata);

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

fireAutoConfigurationImportEvents(configurations,exclusions);

returnnewAutoConfigurationEntry(configurations,exclusions);

}

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

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

3.7@AutoConfigurationPackages

AutoConfigurationPackages是EnableAutoConfiguration上的另一個(gè)核心注解類(lèi),官方解釋為:

Indicatesthatthepackagecontainingtheannotatedclassshouldberegistered

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

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import(AutoConfigurationPackages.Registrar.class)

public@interfaceAutoConfigurationPackage{

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

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

staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{

//注冊(cè)BEAN的定義信息

@Override

publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){

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

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

@Override

publicSetObjectdetermineImports(AnnotationMetadatametadata){

returnCollections.singleton(newPackageImport(metadata));

}

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

/**

*Wrapperforapackageimport.

privatestaticfinalclassPackageImport{

privatefinalStringpackageName;

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

PackageImport(AnnotationMetadatametadata){

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

//獲取指定包名稱(chēng)

publicStringgetPackageName(){

returnthis.packageName;

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

@Override

publicbooleanequals(Objectobj){

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

returnfalse;

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

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

@Override

publicinthashCode(){

returnthis.packageName.hashCode();

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

@Override

publicStringtoString(){

return"PackageImport"+this.packageName;

}

內(nèi)部斷點(diǎn)跟蹤的話(huà),可以看到它記錄的是我們啟動(dòng)類(lèi)所在的包名。這也就是為什么不需要指定掃描包路徑,也會(huì)加載啟動(dòng)類(lèi)所在包下面的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. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論