上一篇www.reibang.com/p/a2d575fb52f5中我們閱讀完了構(gòu)造方法所做的一些的事情。接下來(lái)就是SpringApplication中的run方法力九,いくぞ!邑闺!跌前。直接上源碼截圖:
看著也不是太長(zhǎng),我們先看返回類型陡舅,ConfigurableApplicationContext ?這是一個(gè)interface舒萎,單從名字直譯成可配置的應(yīng)用上下文,對(duì)spring了解的人肯定知道ApplicationContext蹭沛,所以猜測(cè)估計(jì)是跟ApplicationContext有關(guān)系。我們看下此接口的父類關(guān)系圖:
繼承了一個(gè)Closeable 接口章鲤,一個(gè)Lifecyle 生命周期接口摊灭,還有一個(gè)ApplicationContext接口,我們注意看ApplicationContext主要繼承了BeanFactory和ResourceLoader的一些列子接口败徊,加上一個(gè)ApplicationEventPublisher(事件發(fā)布)帚呼。也就是說(shuō)ConfigurableApplicationContext具有資源加載,事件發(fā)布皱蹦,IOC容器等功能煤杀。
然后我們看run的方法體。StopWatch類里面沒(méi)什么東西沪哺,就是記錄一些運(yùn)行時(shí)間沈自,運(yùn)行的狀態(tài)記錄等,接著往下走辜妓。
1.this.configureHeadlessProperty() 設(shè)置是否是headless模式(java se的系統(tǒng)的一種設(shè)置模式枯途,我也不清楚,具體請(qǐng)搜索)籍滴,上一遍中構(gòu)造函數(shù)初始化的其中一個(gè)成員變量headless在這里起到作用酪夷。
2.SpringApplicationRunListeners listeners =this.getRunListeners(args);? 這個(gè)方法getRunListeners(args)跟構(gòu)造函數(shù)的中的setInitializers和setListeners方法類似,會(huì)在spring.factories文件中尋找SpringApplicationRunListener對(duì)應(yīng)的實(shí)現(xiàn)類的名字孽惰,并且利用反射構(gòu)造實(shí)例晚岭,
最終得到SpringApplicationRunListener接口的實(shí)現(xiàn)類EventPublishingRunListener的對(duì)象,并且該對(duì)象持有SpringApplication的引用勋功,把EventPublishingRunListener對(duì)象實(shí)例放到SpringApplicationRunListeners這個(gè)容器里面坦报,由SpringApplicationRunListeners對(duì)象來(lái)管理(其實(shí)就是一個(gè)ArrayList來(lái)存放,里面就一個(gè)EventPublishingRunListener實(shí)例)SpringApplicationRunListener的對(duì)象库说。
3.listeners.starting();spring正在啟動(dòng), 此方法會(huì)遍歷listeners容器(ArrayList)里面所有的SpringApplicationRunListener對(duì)象的starting方法燎竖,其實(shí)就是調(diào)用EventPublishingRunListener的starting()璃弄。關(guān)鍵的地方來(lái)了,請(qǐng)看好:
我們看到starting的實(shí)現(xiàn)构回,里面有個(gè)SimpleApplicationEventMulticaster夏块,這個(gè)對(duì)象就是負(fù)責(zé)廣播ApplicationEvent事件,那么既然是廣播事件纤掸,我們需要知道幾件事情:1.聽(tīng)眾是誰(shuí) 2.什么事件 3聽(tīng)眾如何接收.4接受到如何處理脐供。我點(diǎn)開(kāi)SimpleApplicationEventMulticaster的源碼
? ? 1.事件是什么,事件就是ApplicationStartedEvent(繼承ApplicationEvent)借跪。從類名上可以看出其實(shí)就是發(fā)出了一個(gè)應(yīng)用開(kāi)始啟動(dòng)的信號(hào)了政己。
? ? 2. 聽(tīng)眾呢?開(kāi)始我以為 聽(tīng)眾就是SpringApplication里的所有的ApplicationListener對(duì)象掏愁,這些對(duì)象 我們?cè)谏弦黄械弥猄pringApplication的構(gòu)造函數(shù)中已經(jīng)初始化好了歇由。但是請(qǐng)看SimpleApplicationEventMulticaster里面的第二個(gè)multicastEvent方法 會(huì)調(diào)用getApplciationListeners,這個(gè)方法會(huì)對(duì)? ? SpringApplication? 所持有的所有ApplicationListener對(duì)象做一個(gè)過(guò)濾果港,過(guò)濾那些能處理ApplicationStartedEvent事件的監(jiān)聽(tīng)器沦泌,也就是說(shuō)不是所有的ApplicationListener都對(duì)這個(gè)事件感興趣或者說(shuō)能處理改事件。最終有5個(gè)listener對(duì)該事件感興趣辛掠。
? ? 3.接下來(lái)就是事件的處理了谢谦,我們從SimpleApplicationEventMulticaster可以得出其實(shí)就是ApplicationListener的onApplication的方法處理接受到的event。那么這5個(gè)類如何處理萝衩,其實(shí)可以通過(guò)類名去猜測(cè)出一些東西回挽,具體先留著后面去一個(gè)一個(gè)去解析。
稍微梳理一下就是 SpringApplicationRunListeners 這個(gè)對(duì)象是SpringApplicationRunListener對(duì)象集合的代理猩谊,整個(gè)應(yīng)用的生命周期會(huì)觸發(fā)SpringApplicationRunListeners里面的各個(gè)狀態(tài)方法(starting,environmentPrepared,contextPrepared,contextLoaded,finished)千劈,換種說(shuō)法就是監(jiān)聽(tīng)著spring的各個(gè)生命周期。比如剛剛說(shuō)的應(yīng)用的starting狀態(tài)牌捷,SpringApplicationRunListeners會(huì)讓集合中的所有SpringApplicationRunListener對(duì)象的starting方去處理(在本例中队塘,集合中只有一個(gè)對(duì)象 就是EventPublishingRunListener)。EventPublishingRunListener的處理方式就是讓SpringApplication的的ApplicationListener的一些列相應(yīng)對(duì)象去處理宜鸯,具體就是通過(guò)SimpleApplicationEventMulticaster來(lái)廣播各種事件給ApplicationListener憔古。也就是說(shuō)整個(gè)應(yīng)用的幾個(gè)狀態(tài)或者說(shuō)生命周期(啟動(dòng)狀態(tài),環(huán)境準(zhǔn)備狀態(tài)淋袖,上下文準(zhǔn)備狀態(tài)鸿市,上下文加載狀態(tài),結(jié)束狀態(tài)),都會(huì)通知相應(yīng)的ApplicationListener對(duì)象焰情,然后ApplicationListener對(duì)象去做該做的事情陌凳。
回到文章的開(kāi)頭,run方法接下來(lái)該走到try塊里面了
先看DefaultApplicationArguments ex =new DefaultApplicationArguments(args);將傳經(jīng)來(lái)的參數(shù)args( 本例中其實(shí)就是一段字符串“--debug”内舟,因?yàn)槲沂莇ebug運(yùn)行的)進(jìn)行包裝了一下合敦。
然后ConfigurableEnvironment environment =this.prepareEnvironment(listeners,ex);
主要?jiǎng)?chuàng)建了WEB環(huán)境的上下文,一個(gè)StandardEnvironment验游;方法this.configureEnvironment(environment,applicationArguments.getSourceArgs());配置好系統(tǒng)運(yùn)行的所需要的環(huán)境充岛,里面包含一些配置信息。接著是listeners.environmentPrepared(environment);跟上面的starting方法很像耕蝉,發(fā)出了一個(gè)ApplicationEnvironmentPreparedEvent事件崔梗,廣播給能處理該事件的listener,主要由以下這些:
再次回到run方法:
1.Banner printedBanner =this.printBanner(environment);會(huì)在控制臺(tái)打印spring boot項(xiàng)目啟動(dòng)時(shí)候的圖像等事情垒在。就是下面這貨
2.接下來(lái)是context =this.createApplicationContext();因?yàn)槌蓡T變量webEnvironment為false會(huì)創(chuàng)建一個(gè)AnnotationConfigApplicationContext對(duì)象蒜魄,也是run方法返回的對(duì)象。
3.newFailureAnalyzers(context);實(shí)例化一堆錯(cuò)誤分析器场躯,項(xiàng)目啟動(dòng)報(bào)錯(cuò)了告訴你錯(cuò)誤原因谈为,實(shí)例化的過(guò)程跟前面實(shí)例化listener一模一樣,都是套路踢关。b( ̄▽ ̄)b
4.this.prepareContext(context,environment,listeners,ex,printedBanner);這一步做了很多事情峦阁,先簡(jiǎn)要的說(shuō)下
1) 設(shè)置environment到context中;2)設(shè)置context到ApplicationContextInitializer中耘成;3)廣播一個(gè)contextPrepare事件;4)發(fā)起一個(gè)contextLoad事件
5.最后是一個(gè)contextFinish事件驹闰。
總結(jié):spring從啟動(dòng)到啟動(dòng)結(jié)束中瘪菌,各個(gè)生命周期廣播相應(yīng)的事件出去,然后各個(gè)監(jiān)聽(tīng)器收到廣播消息之后去做對(duì)應(yīng)的事情嘹朗。下面畫的這張圖算是自己的初步理解
但是第一篇中遺留的問(wèn)題這篇文章并沒(méi)有解釋师妙。。屹培。留待以后吧默穴!