網(wǎng)站建設(shè)難點(diǎn)網(wǎng)站推廣優(yōu)化設(shè)計(jì)方案
ApplicationListener是spring boot應(yīng)用啟動(dòng)時(shí)的事件監(jiān)聽器。監(jiān)聽的事件有(包括但不限于):
(1)接下來,我們先通過一個(gè)例子實(shí)現(xiàn)自定義ApplicationListener:
監(jiān)聽器需要實(shí)現(xiàn)ApplicationListener<T>,參數(shù)類型為ApplicationEvent,表示監(jiān)聽所有事件,當(dāng)然也可以將參數(shù)類型設(shè)置為單獨(dú)的事件,下面這個(gè)只會接收ApplicationEnvironmentPreparedEvent事件:
(2)定義了監(jiān)聽器后,還需要配置一下,讓spring boot啟動(dòng)時(shí)加載它,即配置"context.listener.classes"
(3)啟動(dòng)后可以看到,監(jiān)聽器監(jiān)聽了如下事件:
(4)源碼分析,我們來看看自定義的監(jiān)聽器是怎么工作的:
ApplicationListener是采用觀察者模式實(shí)現(xiàn)的,我們的啟動(dòng)時(shí)入口是執(zhí)行SpringApplication.run方法
如下兩處代碼,分別是獲取SpringApplicationRunListeners(這個(gè)是各個(gè)事件的發(fā)布者)和進(jìn)行環(huán)境的準(zhǔn)備,
在環(huán)境準(zhǔn)備好后發(fā)布ApplicationEnvironmentPreparedEvent事件
雖然這里listeners是容器類,但默認(rèn)只有一個(gè)EventPublishingRunListener,我們看一下它是怎么發(fā)布事件的,如下代碼很明顯,進(jìn)行了一個(gè)事件的廣播,但還沒看到廣播給誰,繼續(xù)往下
這里可以看到getApplicationListeners(event, type),就是根據(jù)事件類型獲取需要廣播的ApplicationListener
在調(diào)試狀態(tài)下,我們看一下getApplicationListeners(event, type)有哪些
發(fā)現(xiàn)只有6個(gè)ApplicationListener響應(yīng)了ApplicationEnvironmentPreparedEvent事件,而且沒有我們自定義的ApplicationListener,怎么回事呢?
實(shí)際上,我們的ApplicationListener是通過代理類執(zhí)行的,即上面的DelegatingApplicationListener,我們可以看一下它怎么執(zhí)行的:
上面代碼可以看到代理類也監(jiān)聽了所有的事件,然后在ApplicationEnvironmentPreparedEvent事件時(shí)才初次響應(yīng),并且通過getListeners獲取所有代理的ApplicationListeners,然后它自己實(shí)現(xiàn)了一個(gè)事件廣播器,然后把獲取的ApplicationListeners通過到addApplicationListener加入到廣播器中,最后進(jìn)行事件的廣播轉(zhuǎn)發(fā)。我們重點(diǎn)看一下getListeners,看是如何獲取到我們自定義的ApplicationListeners的:
我們可以看到,是通過我們配置的context.listener.classes獲得類名,然后通過反射實(shí)例化返回。
這樣整個(gè)監(jiān)聽器的過程就完整了。我們注意到代理類是從ApplicationEnvironmentPreparedEvent開始響應(yīng)的,所以之前的事件我們自定義的ApplicationListener是無法監(jiān)聽的。實(shí)際上前面只有一個(gè)ApplicationStartingEvent,此時(shí)應(yīng)用才剛啟動(dòng),也沒啥好監(jiān)聽的。如果需要監(jiān)聽所有的事件可以在自己在spring.factories配置:
在resources下新建META-INF\spring.factoies,然后和spring的監(jiān)聽器配置一樣配置自己定義的監(jiān)聽器,就可以啦