spring-boot啟動(dòng)原理深入(轉(zhuǎn))

spring-boot(http://projects.spring.io/spring-boot/)目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程掖蛤。該框架使用了特定的方式來進(jìn)行配置刨沦,從而使開發(fā)人員不再需要定義樣板化的配置可以使得開發(fā)人員能夠快速開發(fā)部署。


啟動(dòng)流程主要分為三個(gè)部分夕膀,第一部分進(jìn)行SpringApplication的初始化模塊,配置一些基本的環(huán)境變量庭砍、資源吨枉、構(gòu)造器、監(jiān)聽器誓酒,第二部分實(shí)現(xiàn)了應(yīng)用具體的啟動(dòng)方案樟蠕,包括啟動(dòng)流程的監(jiān)聽模塊、加載配置環(huán)境模塊靠柑、及核心的創(chuàng)建上下文環(huán)境模塊寨辩,第三部分是自動(dòng)化配置模塊,該模塊作為springboot自動(dòng)配置核心.


啟動(dòng)

每個(gè)SpringBoot程序都有一個(gè)主入口歼冰,也就是main方法靡狞,main里面調(diào)用SpringApplication.run()啟動(dòng)整個(gè)spring-boot程序,該方法所在類主要需要使用@SpringBootApplication注解隔嫡,@SpringBootApplication包括三個(gè)注解甸怕,功能如下:

@EnableAutoConfiguration:SpringBoot根據(jù)應(yīng)用所聲明的依賴來對(duì)Spring框架進(jìn)行自動(dòng)配置@SpringBootConfiguration(內(nèi)部為@Configuration):被標(biāo)注的類等于在spring的XML配置文件中(applicationContext.xml)甘穿,裝配所有bean事務(wù),提供了一個(gè)spring的上下文環(huán)境@ComponentScan:組件掃描梢杭,可自動(dòng)發(fā)現(xiàn)和裝配Bean温兼,默認(rèn)掃描SpringApplication的run方法里的Booter.class所在的包路徑下文件,所以最好將該啟動(dòng)類放到根包路徑下武契。

進(jìn)入SpringApplication.run()方法

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

這里主要是為SpringApplication對(duì)象賦一些初值咒唆。構(gòu)造函數(shù)執(zhí)行完畢后届垫,回到run方法

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

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

2.加載SpringBoot配置環(huán)境(ConfigurableEnvironment),如果是通過web容器發(fā)布钧排,會(huì)加載StandardEnvironment敦腔,其最終也是繼承了ConfigurableEnvironment,類圖如下

可以看出恨溜,*Environment最終都實(shí)現(xiàn)了PropertyResolver接口,平時(shí)通過environment對(duì)象獲取配置文件中指定Key對(duì)應(yīng)的value方法時(shí)找前,就是調(diào)用了propertyResolver接口的getProperty方法

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

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

方法會(huì)先獲取顯式設(shè)置的應(yīng)用上下文(applicationContextClass),如果不存在躺盛,再加載默認(rèn)的環(huán)境配置(通過是否是web environment判斷)项戴,默認(rèn)選擇AnnotationConfigApplicationContext注解上下文(通過掃描所有注解類來加載bean),最后通過BeanUtils實(shí)例化上下文對(duì)象槽惫,并返回周叮,ConfigurableApplicationContext類圖如下:

主要看其繼承的兩個(gè)方向:

LifeCycle:生命周期類,定義了start啟動(dòng)界斜、stop結(jié)束仿耽、isRunning是否運(yùn)行中等生命周期空值方法

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

5.回到run方法內(nèi)各薇,prepareContext方法將listeners项贺、environment、applicationArguments峭判、banner等重要組件與上下文對(duì)象關(guān)聯(lián)

6.接下來的refreshContext(context)方法(初始化方法如下)將是實(shí)現(xiàn)spring-boot-starter-*(mybatis开缎、redis等)自動(dòng)化配置的關(guān)鍵,包括spring.factories的加載林螃,bean的實(shí)例化等核心工作奕删。

refresh方法

配置結(jié)束后,Springboot做了一些基本的收尾工作疗认,返回了應(yīng)用環(huán)境上下文完残》疲回顧整體流程,Springboot的啟動(dòng)坏怪,主要?jiǎng)?chuàng)建了配置環(huán)境(environment)贝润、事件監(jiān)聽(listeners)、應(yīng)用上下文(applicationContext)铝宵,并基于以上條件打掘,在容器中開始實(shí)例化需要的Bean,至此鹏秋,通過SpringBoot啟動(dòng)的程序已經(jīng)構(gòu)造完成尊蚁,接下是自動(dòng)化配置是如何實(shí)現(xiàn)。


自動(dòng)化配置:

無論是應(yīng)用初始化還是具體的執(zhí)行過程侣夷,都調(diào)用了SpringBoot自動(dòng)配置模塊


SpringBoot自動(dòng)配置模塊

該配置模塊的主要使用到了SpringFactoriesLoader横朋,即Spring工廠加載器,該對(duì)象提供了loadFactoryNames方法百拓,入?yún)閒actoryClass和classLoader琴锭,即需要傳入上圖中的工廠類名稱和對(duì)應(yīng)的類加載器,方法會(huì)根據(jù)指定的classLoader衙传,加載該類加器搜索路徑下的指定文件决帖,即spring.factories文件,傳入的工廠類為接口蓖捶,而文件中對(duì)應(yīng)的類則是接口的實(shí)現(xiàn)類地回,或最終作為實(shí)現(xiàn)類,所以文件中一般為如下圖這種一對(duì)多的類名集合俊鱼,獲取到這些實(shí)現(xiàn)類的類名后刻像,loadFactoryNames方法返回類名集合,方法調(diào)用方得到這些集合后并闲,再通過反射獲取這些類的類對(duì)象细睡、構(gòu)造方法,最終生成實(shí)例

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

下圖有助于形象理解自動(dòng)配置流程


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

mybatis-spring-boot-starter焙蚓、spring-boot-starter-web等組件的META-INF文件下均含有spring.factories文件纹冤,自動(dòng)配置模塊中,SpringFactoriesLoader收集到文件中的類全名并返回一個(gè)類全名的數(shù)組购公,返回的類全名通過反射被實(shí)例化萌京,就形成了具體的工廠實(shí)例,工廠實(shí)例來生成組件具體需要的bean宏浩。

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

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

該方法在springboot啟動(dòng)流程——bean實(shí)例化前被執(zhí)行比庄,返回要實(shí)例化的類信息列表求妹。如果獲取到類信息乏盐,spring自然可以通過類加載器將類加載到j(luò)vm中,現(xiàn)在已經(jīng)通過spring-boot的starter依賴方式依賴了需要的組件制恍,那么這些組建的類信息在select方法中也是可以被獲取到的

該方法中的getCandidateConfigurations方法父能,通過方法注釋了解到,其返回一個(gè)自動(dòng)配置類的類名列表净神,方法調(diào)用了loadFactoryNames方法何吝,查看該方法

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

進(jìn)入org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration中爱榕,主要看一下類頭

發(fā)現(xiàn)@Spring的Configuration,儼然是一個(gè)通過注解標(biāo)注的springBean坡慌,繼續(xù)向下看黔酥,

@ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class})這個(gè)注解的意思是:當(dāng)存在SqlSessionFactory.class, SqlSessionFactoryBean.class這兩個(gè)類時(shí)才解析MybatisAutoConfiguration配置類,否則不解析這一個(gè)配置類,make sence洪橘,需要mybatis返回會(huì)話對(duì)象跪者,就必須有會(huì)話工廠相關(guān)類

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

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

以上配置可以保證sqlSessionFactory坑夯、sqlSessionTemplate、dataSource等mybatis所需的組件均可被自動(dòng)配置抡四,@Configuration注解已經(jīng)提供了Spring的上下文環(huán)境,所以以上組件的配置方式與Spring啟動(dòng)時(shí)通過mybatis.xml文件進(jìn)行配置起到一個(gè)效果仗谆。通過分析可以發(fā)現(xiàn)指巡,只要一個(gè)基于SpringBoot項(xiàng)目的類路徑下存在SqlSessionFactory.class, SqlSessionFactoryBean.class,并且容器中已經(jīng)注冊了dataSourceBean隶垮,就可以觸發(fā)自動(dòng)化配置藻雪,意思說只要在maven的項(xiàng)目中加入了mybatis所需要的若干依賴,就可以觸發(fā)自動(dòng)配置狸吞,但引入mybatis原生依賴的話勉耀,每集成一個(gè)功能都要去修改其自動(dòng)化配置類,那就得不到開箱即用的效果了蹋偏。所以Spring-boot為提供了統(tǒng)一的starter可以直接配置好相關(guān)的類便斥,觸發(fā)自動(dòng)配置所需的依賴(mybatis)如下:

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

因?yàn)閙aven依賴的傳遞性,只要依賴starter就可以依賴到所有需要自動(dòng)配置的類威始,實(shí)現(xiàn)開箱即用的功能枢纠。也體現(xiàn)出Springboot簡化了Spring框架帶來的大量XML配置以及復(fù)雜的依賴管理,讓開發(fā)人員可以更加關(guān)注業(yè)務(wù)邏輯的開發(fā)黎棠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末晋渺,一起剝皮案震驚了整個(gè)濱河市镰绎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌木西,老刑警劉巖畴栖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異八千,居然都是意外死亡吗讶,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門叼丑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來关翎,“玉大人,你說我怎么就攤上這事鸠信∽萸蓿” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵星立,是天一觀的道長爽茴。 經(jīng)常有香客問我,道長绰垂,這世上最難降的妖魔是什么室奏? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮劲装,結(jié)果婚禮上胧沫,老公的妹妹穿的比我還像新娘。我一直安慰自己占业,他們只是感情好绒怨,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谦疾,像睡著了一般南蹂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上念恍,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天六剥,我揣著相機(jī)與錄音,去河邊找鬼峰伙。 笑死疗疟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的词爬。 我是一名探鬼主播秃嗜,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锅锨?” 一聲冷哼從身側(cè)響起叽赊,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎必搞,沒想到半個(gè)月后必指,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恕洲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年塔橡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霜第。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡葛家,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泌类,到底是詐尸還是另有隱情癞谒,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布刃榨,位于F島的核電站弹砚,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏枢希。R本人自食惡果不足惜桌吃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望苞轿。 院中可真熱鬧茅诱,春花似錦、人聲如沸搬卒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秀睛。三九已至,卻和暖如春莲祸,著一層夾襖步出監(jiān)牢的瞬間蹂安,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國打工锐帜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留田盈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓缴阎,卻偏偏與公主長得像允瞧,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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