自動(dòng)配置(啟動(dòng)流程)

2.2 自動(dòng)配置(啟動(dòng)流程)


概念:能夠在我們添加jar包依賴的時(shí)候,自動(dòng)為我們配置一些組件的相關(guān)配置,我們無需配置或者只需要少量配置就能運(yùn)行編寫的項(xiàng)目


問題:Spring Boot到底是如何進(jìn)行自動(dòng)配置的蒜焊,都把哪些組件進(jìn)行了自動(dòng)配置永部?


Spring Boot應(yīng)用的啟動(dòng)入口是@SpringBootApplication注解標(biāo)注類中的main()方法,???????? @SpringBootApplication能夠掃描Spring組件并自動(dòng)配置Spring Boot?


下面碱鳞,查看@SpringBootApplication內(nèi)部源碼進(jìn)行分析 侵佃,核心代碼具體如下


java

@SpringBootApplication

public class SpringbootDemoApplication {


??public static void main(String[] args) {

?????SpringApplication.run(SpringbootDemoApplication.class, args);

?? }

}

java

@Target({ElementType.TYPE}) //注解的適用范圍,Type表示注解可以描述在類麻昼、接口、注解或枚舉中

@Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期馋辈,Runtime運(yùn)行時(shí)

@Documented //表示注解可以記錄在javadoc中

@Inherited?//表示可以被子類繼承該注解

@SpringBootConfiguration???? //標(biāo)明該類為配置類

@EnableAutoConfiguration???? //啟動(dòng)自動(dòng)配置功能

@ComponentScan(??????????????? //包掃描器

???excludeFilters = {@Filter(

???type = FilterType.CUSTOM,

???classes = {TypeExcludeFilter.class}

), @Filter(

???type = FilterType.CUSTOM,

???classes = {AutoConfigurationExcludeFilter.class}

)}

)

public @interface SpringBootApplication {


}


?????????從上述源碼可以看出涌献,@SpringBootApplication注解是一個(gè)組合注解,前面 4 個(gè)是注解的元數(shù)據(jù)信息首有, 我們主要看后面 3 個(gè)注解:@SpringBootConfiguration、@EnableAutoConfiguration枢劝、@ComponentScan三個(gè)核心注解井联,關(guān)于這三個(gè)核心注解的相關(guān)說明具體如下:


1.@SpringBootConfiguration注解


@SpringBootConfiguration注解表示Spring Boot配置類。查看@SpringBootConfiguration注解源碼您旁,核心代碼具體如下烙常。


java

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Configuration //配置IOC容器

public @interface SpringBootConfiguration {

}


?????????從上述源碼可以看出,@SpringBootConfiguration注解內(nèi)部有一個(gè)核心注解@Configuration鹤盒,該注解是Spring框架提供的蚕脏,表示當(dāng)前類為一個(gè)配置類(XML配置文件的注解表現(xiàn)形式),并可以被組件掃描器掃描侦锯。由此可見驼鞭,@SpringBootConfiguration注解的作用與@Configuration注解相同,都是標(biāo)識(shí)一個(gè)可以被組件掃描器掃描的配置類尺碰,只不過@SpringBootConfiguration是被Spring Boot進(jìn)行了重新封裝命名而已?


2.@EnableAutoConfiguration注解


?????????@EnableAutoConfiguration注解表示開啟自動(dòng)配置功能挣棕,該注解是Spring

Boot框架最重要的注解译隘,也是實(shí)現(xiàn)自動(dòng)化配置的注解。同樣洛心,查看該注解內(nèi)部查看源碼信息固耘,核心代碼具體如下 ?

?????????可以發(fā)現(xiàn)它是一個(gè)組合注解,Spring 中有很多以Enable開頭的注解词身,其作用就是借助@Import來收集并注冊(cè)特定場(chǎng)景相關(guān)的bean厅目,并加載到IoC容器。@EnableAutoConfiguration就是借助@Import來收集所有符合自動(dòng)配置條件的bean定義法严,并加載到IoC容器损敷。

???????下面,對(duì)這兩個(gè)核心注解分別講解 :

(1)@AutoConfigurationPackage注解

查看@AutoConfigurationPackage注解內(nèi)部源碼信息渐夸,核心代碼具體如下:

java

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Inherited

@Import({Registrar.class})????? //導(dǎo)入Registrar中注冊(cè)的組件

public @interface AutoConfigurationPackage

{

}

?????????從上述源碼可以看出嗤锉,@AutoConfigurationPackage注解的功能是由@Import注解實(shí)現(xiàn)的,它是spring框架的底層注解墓塌,它的作用就是給容器中導(dǎo)入某個(gè)組件類瘟忱,例如@Import(AutoConfigurationPackages.Registrar.class),它就是將Registrar這個(gè)組件類導(dǎo)入到容器中苫幢,可查看Registrar類中registerBeanDefinitions方法访诱,這個(gè)方法就是導(dǎo)入組件類的具體實(shí)現(xiàn) :

?????????從上述源碼可以看出,在Registrar類中有一個(gè)registerBeanDefinitions()方法韩肝,使用Debug模式啟動(dòng)項(xiàng)目触菜,?????? 可以看到選中的部分就是com.lagou。也就是說哀峻,@AutoConfigurationPackage注解的主要作用就是將主程序類所在包及所有子包下的組件到掃描到spring容器中涡相。

因此 在定義項(xiàng)目包結(jié)構(gòu)時(shí),要求定義的包結(jié)構(gòu)非常規(guī)范剩蟀,項(xiàng)目主程序啟動(dòng)類要定義在最外層的根目錄位置催蝗,然后在根目錄位置內(nèi)部建立子包和類進(jìn)行業(yè)務(wù)開發(fā),這樣才能夠保證定義的類能夠被組件掃描器掃描?


? (2)@Import({AutoConfigurationImportSelector.class}):將AutoConfigurationImportSelector**這個(gè)類導(dǎo)入到spring容器中育特,**AutoConfigurationImportSelector**可以幫助springboot應(yīng)用將所有符合條件的@Configuration配置都加載到當(dāng)前SpringBoot創(chuàng)建并使用的IoC容器(ApplicationContext)中

繼續(xù)研究**AutoConfigurationImportSelector**這個(gè)類丙号,通過源碼分析這個(gè)類中是通過selectImports這個(gè)方法告訴springboot都需要導(dǎo)入那些組件:

深入研究loadMetadata方法

深入getCandidateConfigurations方法

個(gè)方法中有一個(gè)重要方法loadFactoryNames,這個(gè)方法是讓SpringFactoryLoader去加載一些組件的名字缰冤。


繼續(xù)點(diǎn)開loadFactory方法


java

?public static ListloadFactoryNames(Class factoryClass, @Nullable ClassLoaderclassLoader) {


???????//獲取出入的鍵

???????String factoryClassName = factoryClass.getName();

???????return(List)loadSpringFactories(classLoader).getOrDefault(factoryClassName,Collections.emptyList());

??? }


???private static Map>loadSpringFactories(@Nullable ClassLoader classLoader) {

???????MultiValueMap result =(MultiValueMap)cache.get(classLoader);

???????if (result != null) {

???????????return result;

???????} else {

???????????try {

??????????????? //如果類加載器不為null犬缨,則加載類路徑下spring.factories文件,將其中設(shè)置的配置類的全路徑信息封裝為Enumeration類對(duì)象

??????????????? Enumeration urls =classLoader != null ?classLoader.getResources("META-INF/spring.factories") :ClassLoader.getSystemResources("META-INF/spring.factories");

??????????????? LinkedMultiValueMap result =new LinkedMultiValueMap();

??????????????? //循環(huán)Enumeration類對(duì)象棉浸,根據(jù)相應(yīng)的節(jié)點(diǎn)信息生成Properties對(duì)象怀薛,通過傳入的鍵獲取值,在將值切割為一個(gè)個(gè)小的字符串轉(zhuǎn)化為Array迷郑,方法result集合中

??????????????? while(urls.hasMoreElements()) {

??????????????????? URL url =(URL)urls.nextElement();

??????????????????? UrlResource resource = newUrlResource(url);

??????????????????? Properties properties =PropertiesLoaderUtils.loadProperties(resource);

??????????????????? Iterator var6 =properties.entrySet().iterator();

??????????????????? while(var6.hasNext()) {

??????????????????????? Entry entry= (Entry)var6.next();

??????????????????????? String factoryClassName= ((String)entry.getKey()).trim();

??????????????????????? String[] var9 =StringUtils.commaDelimitedListToStringArray((String)entry.getValue());

??????????????????????? int var10 =var9.length;

??????????????????????? for(int var11 = 0;var11 < var10; ++var11) {

??????????????????????????? String factoryName= var9[var11];

???????????????????????????result.add(factoryClassName, factoryName.trim());

??????????????????????? }

??????????????????? }

??????????????? }

??????????????? cache.put(classLoader, result);

??????????????? return result;

會(huì)去讀取一個(gè)sprin? g.factories的文件乾戏,讀取不到會(huì)表這個(gè)錯(cuò)誤迂苛,我們繼續(xù)根據(jù)會(huì)看到,最終路徑的長(zhǎng)這樣鼓择,而這個(gè)是spring提供的一個(gè)工具類

java

public final class SpringFactoriesLoader {

???public static final String FACTORIES_RESOURCE_LOCATION ="META-INF/spring.factories";

}


它其實(shí)是去加載一個(gè)外部的文件三幻,而這文件是在

@EnableAutoConfiguration就是從classpath中搜尋META-INF/spring.factories配置文件,并將其中org.springframework.boot.autoconfigure.EnableutoConfiguration對(duì)應(yīng)的配置項(xiàng)通過反射(Java Refletion)實(shí)例化為對(duì)應(yīng)的標(biāo)注了@Configuration的JavaConfig形式的配置類呐能,并加載到IOC容器中 ? ? ??

?以剛剛的項(xiàng)目為例念搬,在項(xiàng)目中加入了Web環(huán)境依賴啟動(dòng)器,對(duì)應(yīng)的WebMvcAutoConfiguration自動(dòng)配置類就會(huì)生效摆出,打開該自動(dòng)配置類會(huì)發(fā)現(xiàn)朗徊,在該配置類中通過全注解配置類的方式對(duì)Spring MVC運(yùn)行所需環(huán)境進(jìn)行了默認(rèn)配置,包括默認(rèn)前綴偎漫、默認(rèn)后綴爷恳、視圖解析器、MVC校驗(yàn)器等象踊。而這些自動(dòng)配置類的本質(zhì)是傳統(tǒng)Spring MVC框架中對(duì)應(yīng)的XML配置文件温亲,只不過在Spring Boot中以自動(dòng)配置類的形式進(jìn)行了預(yù)先配置。因此杯矩,在Spring Boot項(xiàng)目中加入相關(guān)依賴啟動(dòng)器后栈虚,基本上不需要任何配置就可以運(yùn)行程序,當(dāng)然史隆,我們也可以對(duì)這些自動(dòng)配置類中默認(rèn)的配置進(jìn)行更改 ?

總結(jié)

?? 因此springboot底層實(shí)現(xiàn)自動(dòng)配置的步驟是:

1. springboot應(yīng)用啟動(dòng)魂务;

2. @SpringBootApplication起作用;

3. @EnableAutoConfiguration泌射;

4. @AutoConfigurationPackage:這個(gè)組合注解主要是@Import(AutoConfigurationPackages.Registrar.class)粘姜,它通過將Registrar類導(dǎo)入到容器中,而Registrar類作用是掃描主配置類同級(jí)目錄以及子包熔酷,并將相應(yīng)的組件導(dǎo)入到springboot創(chuàng)建管理的容器中孤紧;

5.@Import(AutoConfigurationImportSelector.class):它通過將AutoConfigurationImportSelector類導(dǎo)入到容器中,AutoConfigurationImportSelector類作用是通過selectImports方法執(zhí)行的過程中纯陨,會(huì)使用內(nèi)部工具類SpringFactoriesLoader,查找classpath上所有jar包中的META-INF/spring.factories進(jìn)行加載留储,實(shí)現(xiàn)將配置類信息交給SpringFactory加載器進(jìn)行一系列的容器創(chuàng)建過程

3. @ComponentScan注解?

?????????@ComponentScan注解具體掃描的包的根路徑由Spring Boot項(xiàng)目主程序啟動(dòng)類所在包位置決定翼抠,在掃描過程中由前面介紹的@AutoConfigurationPackage注解進(jìn)行解析,從而得到Spring

Boot項(xiàng)目主程序啟動(dòng)類所在包的具體位置?

總結(jié):

?@SpringBootApplication的注解的功能就分析差不多了获讳, 簡(jiǎn)單來說就是 3 個(gè)注解的組合注解:

java

|- @SpringBootConfiguration

?? |-@Configuration? //通過javaConfig的方式來添加組件到IOC容器中

|- @EnableAutoConfiguration

?? |-@AutoConfigurationPackage //自動(dòng)配置包阴颖,與@ComponentScan掃描到的添加到IOC

?? |-@Import(AutoConfigurationImportSelector.class) //到META-INF/spring.factories中定義的bean添加到IOC容器中

|- @ComponentScan //包掃描

剛學(xué)了拉勾教育的《Java工程師高薪訓(xùn)練營》,看到剛學(xué)到的點(diǎn)就回答了丐膝。希望拉勾能給我推到想去的公司量愧,目標(biāo):字節(jié)<鼐铡!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末偎肃,一起剝皮案震驚了整個(gè)濱河市煞烫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌累颂,老刑警劉巖滞详,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異紊馏,居然都是意外死亡料饥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門朱监,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岸啡,“玉大人,你說我怎么就攤上這事赫编⊙舱海” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵沛慢,是天一觀的道長(zhǎng)赡若。 經(jīng)常有香客問我,道長(zhǎng)团甲,這世上最難降的妖魔是什么逾冬? 我笑而不...
    開封第一講書人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮躺苦,結(jié)果婚禮上身腻,老公的妹妹穿的比我還像新娘。我一直安慰自己匹厘,他們只是感情好嘀趟,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著愈诚,像睡著了一般她按。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炕柔,一...
    開封第一講書人閱讀 49,850評(píng)論 1 290
  • 那天酌泰,我揣著相機(jī)與錄音,去河邊找鬼匕累。 笑死陵刹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的欢嘿。 我是一名探鬼主播衰琐,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼也糊,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了羡宙?” 一聲冷哼從身側(cè)響起狸剃,我...
    開封第一講書人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎辛辨,沒想到半個(gè)月后捕捂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斗搞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年指攒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僻焚。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡允悦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出虑啤,到底是詐尸還是另有隱情隙弛,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布狞山,位于F島的核電站全闷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏萍启。R本人自食惡果不足惜总珠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勘纯。 院中可真熱鬧局服,春花似錦、人聲如沸驳遵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堤结。三九已至唆迁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間竞穷,已是汗流浹背唐责。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留来庭,地道東北人妒蔚。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓穿挨,卻偏偏與公主長(zhǎng)得像月弛,于是被迫代替她去往敵國和親肴盏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349