上一篇www.lxweimin.com/p/a2d575fb52f5中我們閱讀完了構造方法所做的一些的事情。接下來就是SpringApplication中的run方法,いくぞ!!。直接上源碼截圖:
看著也不是太長,我們先看返回類型,ConfigurableApplicationContext ?這是一個interface,單從名字直譯成可配置的應用上下文,對spring了解的人肯定知道ApplicationContext,所以猜測估計是跟ApplicationContext有關系。我們看下此接口的父類關系圖:
繼承了一個Closeable 接口,一個Lifecyle 生命周期接口,還有一個ApplicationContext接口,我們注意看ApplicationContext主要繼承了BeanFactory和ResourceLoader的一些列子接口,加上一個ApplicationEventPublisher(事件發布)。也就是說ConfigurableApplicationContext具有資源加載,事件發布,IOC容器等功能。
然后我們看run的方法體。StopWatch類里面沒什么東西,就是記錄一些運行時間,運行的狀態記錄等,接著往下走。
1.this.configureHeadlessProperty() 設置是否是headless模式(java se的系統的一種設置模式,我也不清楚,具體請搜索),上一遍中構造函數初始化的其中一個成員變量headless在這里起到作用。
2.SpringApplicationRunListeners listeners =this.getRunListeners(args);? 這個方法getRunListeners(args)跟構造函數的中的setInitializers和setListeners方法類似,會在spring.factories文件中尋找SpringApplicationRunListener對應的實現類的名字,并且利用反射構造實例,
最終得到SpringApplicationRunListener接口的實現類EventPublishingRunListener的對象,并且該對象持有SpringApplication的引用,把EventPublishingRunListener對象實例放到SpringApplicationRunListeners這個容器里面,由SpringApplicationRunListeners對象來管理(其實就是一個ArrayList來存放,里面就一個EventPublishingRunListener實例)SpringApplicationRunListener的對象。
3.listeners.starting();spring正在啟動, 此方法會遍歷listeners容器(ArrayList)里面所有的SpringApplicationRunListener對象的starting方法,其實就是調用EventPublishingRunListener的starting()。關鍵的地方來了,請看好:
我們看到starting的實現,里面有個SimpleApplicationEventMulticaster,這個對象就是負責廣播ApplicationEvent事件,那么既然是廣播事件,我們需要知道幾件事情:1.聽眾是誰 2.什么事件 3聽眾如何接收.4接受到如何處理。我點開SimpleApplicationEventMulticaster的源碼
? ? 1.事件是什么,事件就是ApplicationStartedEvent(繼承ApplicationEvent)。從類名上可以看出其實就是發出了一個應用開始啟動的信號了。
? ? 2. 聽眾呢?開始我以為 聽眾就是SpringApplication里的所有的ApplicationListener對象,這些對象 我們在上一篇中得知SpringApplication的構造函數中已經初始化好了。但是請看SimpleApplicationEventMulticaster里面的第二個multicastEvent方法 會調用getApplciationListeners,這個方法會對? ? SpringApplication? 所持有的所有ApplicationListener對象做一個過濾,過濾那些能處理ApplicationStartedEvent事件的監聽器,也就是說不是所有的ApplicationListener都對這個事件感興趣或者說能處理改事件。最終有5個listener對該事件感興趣。
? ? 3.接下來就是事件的處理了,我們從SimpleApplicationEventMulticaster可以得出其實就是ApplicationListener的onApplication的方法處理接受到的event。那么這5個類如何處理,其實可以通過類名去猜測出一些東西,具體先留著后面去一個一個去解析。
稍微梳理一下就是 SpringApplicationRunListeners 這個對象是SpringApplicationRunListener對象集合的代理,整個應用的生命周期會觸發SpringApplicationRunListeners里面的各個狀態方法(starting,environmentPrepared,contextPrepared,contextLoaded,finished),換種說法就是監聽著spring的各個生命周期。比如剛剛說的應用的starting狀態,SpringApplicationRunListeners會讓集合中的所有SpringApplicationRunListener對象的starting方去處理(在本例中,集合中只有一個對象 就是EventPublishingRunListener)。EventPublishingRunListener的處理方式就是讓SpringApplication的的ApplicationListener的一些列相應對象去處理,具體就是通過SimpleApplicationEventMulticaster來廣播各種事件給ApplicationListener。也就是說整個應用的幾個狀態或者說生命周期(啟動狀態,環境準備狀態,上下文準備狀態,上下文加載狀態,結束狀態),都會通知相應的ApplicationListener對象,然后ApplicationListener對象去做該做的事情。
回到文章的開頭,run方法接下來該走到try塊里面了
先看DefaultApplicationArguments ex =new DefaultApplicationArguments(args);將傳經來的參數args( 本例中其實就是一段字符串“--debug”,因為我是debug運行的)進行包裝了一下。
然后ConfigurableEnvironment environment =this.prepareEnvironment(listeners,ex);
主要創建了WEB環境的上下文,一個StandardEnvironment;方法this.configureEnvironment(environment,applicationArguments.getSourceArgs());配置好系統運行的所需要的環境,里面包含一些配置信息。接著是listeners.environmentPrepared(environment);跟上面的starting方法很像,發出了一個ApplicationEnvironmentPreparedEvent事件,廣播給能處理該事件的listener,主要由以下這些:
再次回到run方法:
1.Banner printedBanner =this.printBanner(environment);會在控制臺打印spring boot項目啟動時候的圖像等事情。就是下面這貨
2.接下來是context =this.createApplicationContext();因為成員變量webEnvironment為false會創建一個AnnotationConfigApplicationContext對象,也是run方法返回的對象。
3.newFailureAnalyzers(context);實例化一堆錯誤分析器,項目啟動報錯了告訴你錯誤原因,實例化的過程跟前面實例化listener一模一樣,都是套路。b( ̄▽ ̄)b
4.this.prepareContext(context,environment,listeners,ex,printedBanner);這一步做了很多事情,先簡要的說下
1) 設置environment到context中;2)設置context到ApplicationContextInitializer中;3)廣播一個contextPrepare事件;4)發起一個contextLoad事件
5.最后是一個contextFinish事件。
總結:spring從啟動到啟動結束中,各個生命周期廣播相應的事件出去,然后各個監聽器收到廣播消息之后去做對應的事情。下面畫的這張圖算是自己的初步理解
但是第一篇中遺留的問題這篇文章并沒有解釋。。。留待以后吧!