Spring事件監聽機制(二)

Spring中的事件監聽
前面我們大致瞭解了一下事件監聽,我們接着來看看Spring中的事件監聽是如何使用的。這裏我選用了springboot 1.5.7的源碼來學習。

在啓動類中執行SpringApplication.run()後,首先會執行SpringApplication類的initialize(Object[] sources)方法,然後初始化initializers和listeners兩個集合,initializers集合存放的是springboot從配置文件自動裝配的6個ApplicationContextInitializer對應的類,listeners集合存放的是從配置文件自動裝配的10個ApplicationListener對應的類。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
這個加載方式是通過讀取配置文件中類的路徑,然後利用反射生成的對象。具體方法如下:
在這裏插入圖片描述

接下來,我們看run(String… args)方法中的執行內容:
在這裏插入圖片描述
首先會通過getRunListeners(String[] args)方法去從配置文件讀取key=SpringApplicationRunListener對應的類名然後通過反射生成對象,這裏就一個EventPublishingRunListener對象。

接着執行listeners.starting();方法。這裏會調用EventPublishingRunListener的starting()方法,查看源碼,我們看到這裏是調用一個廣播器發送廣播的方法
在這裏插入圖片描述
繼續跟蹤,執行到了SimpleApplicationEventMulticaster類中,通過名字我們可以知道這是一個廣播器,用於專門發送事件的。
在這裏插入圖片描述
最終在這裏調用發送事件的方法。這裏的eventType是ApplicationStartedEvent。通過getApplicationListeners(event, type)可以得到4個listener:
LoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
LiquibaseServiceLocatorApplicationListener

注意:這裏有個判斷,如果有Executor不爲空,就說明是開啓線程異步發送的,否則就是同步發送。
我們如何開啓異步發送,這個我們後面說。

我們接着看run()方法中的prepareEnvironment(listeners,applicationArguments);方法:
在這裏插入圖片描述
看到這裏有個listeners.environmentPrepared()方法,跟蹤代碼後發現它調用EventPublishingRunListener的environmentPrepared()方法,它同樣也是執行發送廣播的方法:
在這裏插入圖片描述
它發送廣播時eventType爲ApplicationEnvironmentPreparedEvent。通過getApplicationListeners(event, type) 得到以下7個listener:
ConfigFileApplicationListener
AnsiOutputApplicationListener
LoggingApplicationListener
ClasspathLoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
FileEncodingApplicationListener

繼續看run()方法中的prepareContext()方法,我們看到這裏會執行2個方法listeners.contextPrepared(context); 和 listeners.contextLoaded(context);
跟蹤代碼後發現contextPrepared 沒有執行任何代碼,所以我們不管它。
在這裏插入圖片描述
我們看 listeners.contextLoaded(context); 它調用EventPublishingRunListener的contextLoaded()方法,首先會把我們前面加載得到的10個ApplicationListener對應的對象放到context容器中。接着再發送廣播,這裏的eventType爲ApplicationPreparedEvent,通過getApplicationListeners(event, type) 得到以下4個listener:
ConfigFileApplicationListener
LoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
在這裏插入圖片描述

接着看run()方法中的refreshContext(context);方法,它裏面調用的refresh()方法,看過spring源碼的都應該對這個refresh都應該不陌生。它是spring中很重要的一個方法。

在這裏插入圖片描述

這裏我們主要看關於listener事件的處理。我們先看initApplicationEventMulticaster():
在這裏插入圖片描述
這裏主要是獲取SimpleApplicationEventMulticaster applicationEventMulticaster對象。

接着看registerListeners()方法,這裏會分別把容器中的listener存放在defaultRetriever對象的applicationListeners集合中,defaultRetriever是定義在抽象類AbstractApplicationEventMulticaster中的成員,用來保存所有事件監聽器及其beanName
在這裏插入圖片描述
在這裏插入圖片描述

再執行finishRefresh(),這裏它會先進入EmbeddedWebApplicationContext類的finishRefresh(),然後調用super.finishRefresh();去執行AbstractApplicationContext類的finishRefresh()。

EmbeddedWebApplicationContext類:在這裏插入圖片描述

AbstractApplicationContext類:
在這裏插入圖片描述
在AbstractApplicationContext類的finishRefresh()中它會執行publishEvent()方法去SimpleApplicationEventMulticaster類中發送廣播,此時的type爲ContextRefreshedEvent,getApplicationListeners(event, type) 有如下6個值:
ConfigurationPropertiesBindingPostProcessor
DelegatingApplicationListener
AutoConfigurationReportLoggingInitializer
ClearCacheApplicationListener
SharedMetadataReaderFactoryContextInitializer
ResourceUrlProvider

發送完後又會到EmbeddedWebApplicationContext類的finishRefresh(),此時如果我們得到了一個嵌入式的容器(這裏應該指tomcat),那麼我們同樣會去SimpleApplicationEventMulticaster類中發送廣播,此時的type爲EmbeddedServletContainerInitializedEvent,getApplicationListeners(event, type) 有如下2個值:
DelegatingApplicationListener
ServerPortInfoApplicationContextInitializer

執行完返回到run()方法中,接着執行listeners.finished(context, null),這裏會執行到AbstractApplicationContext類中的publishEvent()方法,最終也會去SimpleApplicationEventMulticaster類中發送廣播,此時的type爲ApplicationReadyEvent,getApplicationListeners(event, type) 有如下3個值:
BackgroundPreinitializer
DelegatingApplicationListener
SpringApplicationAdminMXBeanRegistrar

至此我們springboot在啓動時,事件監聽就全部執行完了。容器也啓動成功了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章