




版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 花兒生肖測(cè)試題及答案
- 紡織原材料采購(gòu)知識(shí)試題及答案
- 裝修違約合同協(xié)議書(shū)
- 門(mén)面轉(zhuǎn)租合同協(xié)議書(shū)范本
- 網(wǎng)絡(luò)電子協(xié)議書(shū)合同
- 短期聘用合同簡(jiǎn)單協(xié)議書(shū)
- 城市生態(tài)修復(fù)項(xiàng)目社會(huì)穩(wěn)定風(fēng)險(xiǎn)評(píng)估報(bào)告:2025年生態(tài)修復(fù)項(xiàng)目風(fēng)險(xiǎn)評(píng)估與風(fēng)險(xiǎn)評(píng)估模型
- 吊車(chē)合同續(xù)簽協(xié)議書(shū)
- 紡織品設(shè)計(jì)要素解析試題及答案
- 承包山地合同協(xié)議書(shū)
- 傳媒公司主播離職協(xié)議書(shū)
- 環(huán)氧樹(shù)脂畢業(yè)設(shè)計(jì)
- 水電廠汛期安全培訓(xùn)
- 代謝性堿中毒護(hù)理課件
- 第四單元 舞蹈音樂(lè)天地-二拍子 四拍子舞曲 童聲合唱《閑聊波爾卡》 課件 2022-2023學(xué)年粵教版初中音樂(lè)九年級(jí)下冊(cè)
- 辦稅服務(wù)外包投標(biāo)方案(完整版)
- 氫氧化鈉介紹msds
- 青甘大環(huán)線路線
- 通信基站維保投標(biāo)方案(技術(shù)方案)
- 信息化運(yùn)維服務(wù)投標(biāo)方案(技術(shù)方案)
- 一方出資金一方出資源合作協(xié)議范本
評(píng)論
0/150
提交評(píng)論