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,類圖如下
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ā)黎棠。