SpringBoot啟動流程解析

寫在前面:

? ? ? ?由于該系統(tǒng)是底層系統(tǒng),以微服務(wù)形式對外暴露dubbo服務(wù)礁鲁,所以本流程中SpringBoot不基于jetty或者tomcat等容器啟動方式發(fā)布服務(wù)八酒,而是以執(zhí)行程序方式啟動來發(fā)布(參考下圖keepRunning方法)。

? ? ? ?本文以調(diào)試一個實際的SpringBoot啟動程序為例,參考流程中主要類類圖鳍悠,來分析其啟動邏輯和自動化配置原理。


總覽:

? ? ? ?上圖為SpringBoot啟動結(jié)構(gòu)圖,我們發(fā)現(xiàn)啟動流程主要分為三個部分监署,第一部分進行SpringApplication的初始化模塊,配置一些基本的環(huán)境變量纽哥、資源钠乏、構(gòu)造器、監(jiān)聽器昵仅,第二部分實現(xiàn)了應(yīng)用具體的啟動方案缓熟,包括啟動流程的監(jiān)聽模塊、加載配置環(huán)境模塊摔笤、及核心的創(chuàng)建上下文環(huán)境模塊够滑,第三部分是自動化配置模塊,該模塊作為springboot自動配置核心吕世,在后面的分析中會詳細討論彰触。在下面的啟動程序中我們會串聯(lián)起結(jié)構(gòu)中的主要功能。

啟動:

? ? ? 每個SpringBoot程序都有一個主入口命辖,也就是main方法况毅,main里面調(diào)用SpringApplication.run()啟動整個spring-boot程序,該方法所在類需要使用@SpringBootApplication注解尔艇,以及@ImportResource注解(if need)尔许,@SpringBootApplication包括三個注解,功能如下:@EnableAutoConfiguration:SpringBoot根據(jù)應(yīng)用所聲明的依賴來對Spring框架進行自動配置

@SpringBootConfiguration(內(nèi)部為@Configuration):被標注的類等于在spring的XML配置文件中(applicationContext.xml)终娃,裝配所有bean事務(wù)味廊,提供了一個spring的上下文環(huán)境

@ComponentScan:組件掃描,可自動發(fā)現(xiàn)和裝配Bean棠耕,默認掃描SpringApplication的run方法里的Booter.class所在的包路徑下文件余佛,所以最好將該啟動類放到根包路徑下

SpringBoot啟動類

首先進入run方法

run方法中去創(chuàng)建了一個SpringApplication實例,在該構(gòu)造方法內(nèi)窍荧,我們可以發(fā)現(xiàn)其調(diào)用了一個初始化的initialize方法

這里主要是為SpringApplication對象賦一些初值辉巡。構(gòu)造函數(shù)執(zhí)行完畢后,我們回到run方法

該方法中實現(xiàn)了如下幾個關(guān)鍵步驟:

1.創(chuàng)建了應(yīng)用的監(jiān)聽器SpringApplicationRunListeners并開始監(jiān)聽

2.加載SpringBoot配置環(huán)境(ConfigurableEnvironment)蕊退,如果是通過web容器發(fā)布郊楣,會加載StandardEnvironment憔恳,其最終也是繼承了ConfigurableEnvironment,類圖如下

可以看出痢甘,*Environment最終都實現(xiàn)了PropertyResolver接口喇嘱,我們平時通過environment對象獲取配置文件中指定Key對應(yīng)的value方法時,就是調(diào)用了propertyResolver接口的getProperty方法

3.配置環(huán)境(Environment)加入到監(jiān)聽器對象中(SpringApplicationRunListeners)

4.創(chuàng)建run方法的返回對象:ConfigurableApplicationContext(應(yīng)用配置上下文)塞栅,我們可以看一下創(chuàng)建方法:

方法會先獲取顯式設(shè)置的應(yīng)用上下文(applicationContextClass)者铜,如果不存在,再加載默認的環(huán)境配置(通過是否是web environment判斷)放椰,默認選擇AnnotationConfigApplicationContext注解上下文(通過掃描所有注解類來加載bean)作烟,最后通過BeanUtils實例化上下文對象,并返回砾医,ConfigurableApplicationContext類圖如下:

主要看其繼承的兩個方向:

LifeCycle:生命周期類拿撩,定義了start啟動、stop結(jié)束如蚜、isRunning是否運行中等生命周期空值方法

ApplicationContext:應(yīng)用上下文類压恒,其主要繼承了beanFactory(bean的工廠類)

5.回到run方法內(nèi),prepareContext方法將listeners错邦、environment探赫、applicationArguments、banner等重要組件與上下文對象關(guān)聯(lián)

6.接下來的refreshContext(context)方法(初始化方法如下)將是實現(xiàn)spring-boot-starter-*(mybatis撬呢、redis等)自動化配置的關(guān)鍵伦吠,包括spring.factories的加載,bean的實例化等核心工作魂拦。

refresh方法

配置結(jié)束后毛仪,Springboot做了一些基本的收尾工作,返回了應(yīng)用環(huán)境上下文芯勘∠溲ィ回顧整體流程,Springboot的啟動荷愕,主要創(chuàng)建了配置環(huán)境(environment)衡怀、事件監(jiān)聽(listeners)、應(yīng)用上下文(applicationContext)路翻,并基于以上條件,在容器中開始實例化我們需要的Bean茄靠,至此茂契,通過SpringBoot啟動的程序已經(jīng)構(gòu)造完成,接下來我們來探討自動化配置是如何實現(xiàn)慨绳。


自動化配置:

? ? ? ?之前的啟動結(jié)構(gòu)圖中掉冶,我們注意到無論是應(yīng)用初始化還是具體的執(zhí)行過程真竖,都調(diào)用了SpringBoot自動配置模塊

SpringBoot自動配置模塊

? ? ? ?該配置模塊的主要使用到了SpringFactoriesLoader,即Spring工廠加載器厌小,該對象提供了loadFactoryNames方法恢共,入?yún)閒actoryClass和classLoader,即需要傳入上圖中的工廠類名稱和對應(yīng)的類加載器璧亚,方法會根據(jù)指定的classLoader讨韭,加載該類加器搜索路徑下的指定文件,即spring.factories文件癣蟋,傳入的工廠類為接口透硝,而文件中對應(yīng)的類則是接口的實現(xiàn)類,或最終作為實現(xiàn)類疯搅,所以文件中一般為如下圖這種一對多的類名集合濒生,獲取到這些實現(xiàn)類的類名后,loadFactoryNames方法返回類名集合幔欧,方法調(diào)用方得到這些集合后罪治,再通過反射獲取這些類的類對象、構(gòu)造方法礁蔗,最終生成實例

工廠接口與其若干實現(xiàn)類接口名稱

下圖有助于我們形象理解自動配置流程

SpringBoot自動化配置關(guān)鍵組件關(guān)系圖?

? ? ? mybatis-spring-boot-starter觉义、spring-boot-starter-web等組件的META-INF文件下均含有spring.factories文件,自動配置模塊中瘦麸,SpringFactoriesLoader收集到文件中的類全名并返回一個類全名的數(shù)組谁撼,返回的類全名通過反射被實例化,就形成了具體的工廠實例滋饲,工廠實例來生成組件具體需要的bean厉碟。

之前我們提到了EnableAutoConfiguration注解,其類圖如下

可以發(fā)現(xiàn)其最終實現(xiàn)了ImportSelector(選擇器)和BeanClassLoaderAware(bean類加載器中間件)屠缭,重點關(guān)注一下AutoConfigurationImportSelector的selectImports方法

該方法在springboot啟動流程——bean實例化前被執(zhí)行箍鼓,返回要實例化的類信息列表。我們知道呵曹,如果獲取到類信息款咖,spring自然可以通過類加載器將類加載到j(luò)vm中,現(xiàn)在我們已經(jīng)通過spring-boot的starter依賴方式依賴了我們需要的組件奄喂,那么這些組建的類信息在select方法中也是可以被獲取到的铐殃,不要急我們繼續(xù)向下分析

該方法中的getCandidateConfigurations方法,通過方法注釋了解到跨新,其返回一個自動配置類的類名列表富腊,方法調(diào)用了loadFactoryNames方法,查看該方法

在上面的代碼可以看到自動配置器會跟根據(jù)傳入的factoryClass.getName()到項目系統(tǒng)路徑下所有的spring.factories文件中找到相應(yīng)的key域帐,從而加載里面的類赘被。我們就選取這個mybatis-spring-boot-autoconfigure下的spring.factories文件

進入org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中是整,主要看一下類頭

發(fā)現(xiàn)@Spring的Configuration,儼然是一個通過注解標注的springBean民假,繼續(xù)向下看浮入,

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})這個注解的意思是:當存在SqlSessionFactory.class, SqlSessionFactoryBean.class這兩個類時才解析MybatisAutoConfiguration配置類,否則不解析這一個配置類,make sence羊异,我們需要mybatis為我們返回會話對象事秀,就必須有會話工廠相關(guān)類

@CondtionalOnBean(DataSource.class):只有處理已經(jīng)被聲明為bean的dataSource

@ConditionalOnMissingBean(MapperFactoryBean.class)這個注解的意思是如果容器中不存在name指定的bean則創(chuàng)建bean注入,否則不執(zhí)行(該類源碼較長球化,篇幅限制不全粘貼)

? ? ? ?以上配置可以保證sqlSessionFactory秽晚、sqlSessionTemplate、dataSource等mybatis所需的組件均可被自動配置筒愚,@Configuration注解已經(jīng)提供了Spring的上下文環(huán)境赴蝇,所以以上組件的配置方式與Spring啟動時通過mybatis.xml文件進行配置起到一個效果。通過分析我們可以發(fā)現(xiàn)巢掺,只要一個基于SpringBoot項目的類路徑下存在SqlSessionFactory.class, SqlSessionFactoryBean.class句伶,并且容器中已經(jīng)注冊了dataSourceBean,就可以觸發(fā)自動化配置陆淀,意思說我們只要在maven的項目中加入了mybatis所需要的若干依賴考余,就可以觸發(fā)自動配置,但引入mybatis原生依賴的話轧苫,每集成一個功能都要去修改其自動化配置類楚堤,那就得不到開箱即用的效果了。所以Spring-boot為我們提供了統(tǒng)一的starter可以直接配置好相關(guān)的類含懊,觸發(fā)自動配置所需的依賴(mybatis)如下:

這里是截取的mybatis-spring-boot-starter的源碼中pom.xml文件中所有依賴:

因為maven依賴的傳遞性身冬,我們只要依賴starter就可以依賴到所有需要自動配置的類,實現(xiàn)開箱即用的功能岔乔。也體現(xiàn)出Springboot簡化了Spring框架帶來的大量XML配置以及復雜的依賴管理酥筝,讓開發(fā)人員可以更加關(guān)注業(yè)務(wù)邏輯的開發(fā)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雏门,一起剝皮案震驚了整個濱河市嘿歌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茁影,老刑警劉巖宙帝,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異募闲,居然都是意外死亡步脓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沪编,“玉大人,你說我怎么就攤上這事年扩∫侠” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵厨幻,是天一觀的道長相嵌。 經(jīng)常有香客問我,道長况脆,這世上最難降的妖魔是什么饭宾? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮格了,結(jié)果婚禮上看铆,老公的妹妹穿的比我還像新娘。我一直安慰自己盛末,他們只是感情好弹惦,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悄但,像睡著了一般棠隐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上檐嚣,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天助泽,我揣著相機與錄音,去河邊找鬼嚎京。 笑死嗡贺,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的挖藏。 我是一名探鬼主播暑刃,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼膜眠!你這毒婦竟也來了岩臣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤宵膨,失蹤者是張志新(化名)和其女友劉穎架谎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辟躏,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡谷扣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片会涎。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡裹匙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出末秃,到底是詐尸還是另有隱情概页,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布练慕,位于F島的核電站惰匙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铃将。R本人自食惡果不足惜项鬼,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望劲阎。 院中可真熱鬧绘盟,春花似錦、人聲如沸悯仙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雁比。三九已至稚虎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間偎捎,已是汗流浹背蠢终。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留茴她,地道東北人寻拂。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像丈牢,于是被迫代替她去往敵國和親祭钉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容