最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

20-Spring高級(jí)容器初始化:Spring是如何基于事件驅(qū)動(dòng)的呢?

2023-06-18 18:51 作者:儒猿課堂  | 我要投稿

開(kāi)篇


上一節(jié),我們了解了Spring如果想要控制一個(gè)bean的實(shí)例化過(guò)程,比如我們想要按照自己的意愿來(lái)控制bean的實(shí)例化,可以通過(guò)自定義BeanPostProcessor來(lái)實(shí)現(xiàn)。

當(dāng)自定義的BeanPostProcessor注冊(cè)到Spring容器后,bean在實(shí)例化開(kāi)始前和結(jié)束后分別都會(huì)調(diào)用BeanPostProcessor接口中的方法,從而實(shí)現(xiàn)介入bean的實(shí)例化的過(guò)程,讓我們有機(jī)會(huì)控制bean的實(shí)例化過(guò)程。


而且,我們也看到了在Spring高級(jí)容器ApplicationContext初始化時(shí),暫時(shí)也只是將各種BeanPostProcessor注冊(cè)到Spring容器中,BeanPostProcessor接口中的方法調(diào)用時(shí)機(jī),我們還得在后面的章節(jié)bean實(shí)例化時(shí)才能看到。


接下來(lái),我們沿著上節(jié)課的分析,繼續(xù)來(lái)看下后面會(huì)再為Spring容器beanFactory擴(kuò)展一些什么樣的功能,這一節(jié)主要包括以下內(nèi)容:

1.看下Application是如何初始化消息源的

2.接下來(lái)再看下Spring中是如何初始化事件廣播器的

3.然后來(lái)看下如何利用Spring中的廣播器來(lái)發(fā)布自定義的事件

4.最后再來(lái)看下Spring中的廣播器是如何通過(guò)監(jiān)聽(tīng)器來(lái)處理事件的


初始化消息源MessageSource


我們繼續(xù)看到refresh方法后面的一些邏輯:

我們到initMessageSource方法中看下:

可以看到,方法initMessageSource中的邏輯還是比較簡(jiǎn)單的,首先通過(guò)getBeanFactory方法獲取Spring容器beanFactory,然后通過(guò)containsLocalBean方法判斷Spring容器中是否存在名稱為MESSAGE_SOURCE_BEAN_NAME的bean。


那MESSAGE_SOURCE_BEAN_NAME是什么呢,我們可以簡(jiǎn)單找一下:

可以看到,MESSAGE_SOURCE_BEAN_NAME其實(shí)就是AbstractApplicationContext中的常量,值為“messageSource”。

這就意味著,如果我們要在xml中配置MessageSource,id屬性的值也得要配置為“messageSource”,這樣的話容器beanFactory才能從容器中獲取到。


但是,如果我們沒(méi)有在xml中配置MessageSource時(shí),接下來(lái)就會(huì)來(lái)到else分支中:

可以看到在else分支中,其實(shí)就是初始化了一個(gè)DelegatingMessageSource類型的對(duì)象,然后將該對(duì)象注冊(cè)到了Spring中,并且該對(duì)象的名稱就為messageSource。


其實(shí),Spring中的MessageSource就是處理國(guó)際化的,那什么是國(guó)際化呢?比如一段文字,在不同的國(guó)家肯定是需要使用不同的語(yǔ)言來(lái)顯示的,就算你是在同一個(gè)國(guó)家如中國(guó),不同地區(qū)的文字也是有差異的如大陸和臺(tái)灣,對(duì)于我們系統(tǒng)而言,就需要根據(jù)當(dāng)前系統(tǒng)選擇的國(guó)家地區(qū),用相應(yīng)的文字來(lái)顯示了。

但是,在日常開(kāi)發(fā)過(guò)程當(dāng)中對(duì)于國(guó)際化的處理,使用Spring中的MessageSource來(lái)支持國(guó)際化的場(chǎng)景已經(jīng)是很少了,所以這里暫時(shí)不再過(guò)多的探討,大家了解下即可。


初始化廣播器ApplicationEventMulticaster


接下來(lái),我們看到refresh方法中的下一個(gè)方法initApplicationEventMulticaster:

我們到方法initApplicationEventMulticaster里面看下:

可以看到邏輯都是類似的,這里主要是看下容器beanFactory中是否存在名稱為APPLICATION_EVENT_MULTICASTER_BEAN_NAME也就是名稱為applicationEventMulticaster的bean。

如果存在的話,直接從容器中獲取出來(lái)并賦值給成員變量applicationEventMulticaster,否則直接創(chuàng)建一個(gè)SimpleApplicationEventMulticaster類型的對(duì)象并設(shè)置到Spring容器beanFactory中。


那什么是SimpleApplicationEventMulticaster呢?剛才我們從beanFactory中獲取對(duì)象時(shí),主要是根據(jù)接口類型為ApplicationEventMulticaster去獲取的,而ApplicationEventMulticaster在Spring中被稱為是事件的廣播器。

在Spring中和事件廣播器ApplicationEventMulticaster息息相關(guān)的另外一個(gè)組件,就是監(jiān)聽(tīng)器ApplicationListener。

在Spring中,廣播器ApplicationEventMulticaster中可以注冊(cè)多個(gè)監(jiān)聽(tīng)器ApplicationListener,當(dāng)特定的事件ApplicationEvent發(fā)生時(shí),就會(huì)觸發(fā)廣播器ApplicationEventMulticaster來(lái)遍歷各個(gè)監(jiān)聽(tīng)器ApplicationListener中的方法,看下到底是哪個(gè)監(jiān)聽(tīng)器負(fù)責(zé)監(jiān)聽(tīng)的事件發(fā)生了,讓指定的監(jiān)聽(tīng)器來(lái)處理。


接下來(lái),我們通過(guò)一個(gè)案例來(lái)看下在Spring中,是如何通過(guò)廣播器和監(jiān)聽(tīng)器來(lái)完成功能的。


如何基于Spring內(nèi)部廣播器發(fā)布事件

首先,我們需要自定義一個(gè)事件類,在Spring中可以通過(guò)繼承抽象類ApplicationEvent創(chuàng)建:

然后,我們?cè)谑录怣yEvent中自定義一個(gè)方法event,方便觸發(fā)該事件時(shí),監(jiān)聽(tīng)器可以回調(diào)該方法執(zhí)行相關(guān)的邏輯,當(dāng)然方法的名稱大家可以自行定義,只要記得在處理事件時(shí)調(diào)用自定義的方法即可。


接著,我們?cè)賱?chuàng)建一個(gè)監(jiān)聽(tīng)事件MyEvent的監(jiān)聽(tīng)器MyListener,監(jiān)聽(tīng)器需要實(shí)現(xiàn)Spring提供的接口ApplicationListener:

然后,在onApplicationEvent方法中,我們可以決定監(jiān)聽(tīng)器要對(duì)那些事件進(jìn)行監(jiān)聽(tīng),可以看到在MyListener監(jiān)聽(tīng)器中的onApplicationEvent方法中,我們規(guī)定只會(huì)處理MyEvent事件。


接著,我們需要將監(jiān)聽(tīng)器配置到xml文件中,這樣Spring在掃描xml文件時(shí),MyListener最終會(huì)被注冊(cè)到Spring容器中:

然后,我們來(lái)看下效果:

可以看到,當(dāng)ClassPathXmlApplicationContext初始化之后,可以通過(guò)調(diào)用ClassPathXmlApplicationContext的publishEvent方法,觸發(fā)我們定義好的MyEvent事件,我們運(yùn)行一下看下:

可以看到,自定義的事件MyEvent的中的event方法成功被調(diào)用了。


看到這里,雖然我們已經(jīng)通過(guò)一個(gè)案例簡(jiǎn)單體驗(yàn)了一下在Spring中,是如何自定義監(jiān)聽(tīng)器和事件的,但是我們目前對(duì)于廣播器ApplicationEventMulticaster在這一過(guò)程中的作用,還是處于模棱兩可的狀態(tài)。

要了解廣播器的功能呢,我們得要沿著案例中的publishEvent方法,看下自定義事件MyEvent是如何發(fā)布且最終被處理的。


Spring中事件是如何發(fā)布的呢?

我們以ClassPathXmlApplicationContext中的publishEvent方法作為入口,來(lái)看下事件MyEvent是如何發(fā)布的:

我們跟進(jìn)到重載方法publishEvent中:

可以看到,首先我們傳進(jìn)來(lái)的event類型,根據(jù)剛才的案例可以知道肯定就是ApplicationEvent的實(shí)例,畢竟MyEvent就是繼承ApplicationEvent接口的,所以接下來(lái)會(huì)將Object類型的event對(duì)象,轉(zhuǎn)換為ApplicationEvent類型的applicationEvent。

接著,我們發(fā)現(xiàn)會(huì)調(diào)用getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType),其中,getApplicationEventMulticaster方法獲取的不就是我們前面看到的廣播器嗎?而廣播器的類型我們前面也看到了,默認(rèn)是為SimpleApplicationEventMulticaster。


所以,我們可以推測(cè)代碼下一步,就要進(jìn)入到SimpleApplicationEventMulticaster中的multicastEvent方法了,現(xiàn)在,我們直接到SimpleApplicationEventMulticaster中的方法multicastEvent里面,看下廣播器是如何處理事件的:

在方法multicastEvent中默認(rèn)是沒(méi)有設(shè)置線程池的,所以executor為空。

接著,我們看到會(huì)通過(guò)getApplicationListeners方法獲取Spring容器中的所有監(jiān)聽(tīng)器,然后依次遍歷處理這些監(jiān)聽(tīng)器,從這里我們初步可以知道,廣播器的作用其實(shí)就是當(dāng)一個(gè)事件發(fā)生時(shí),通知Spring容器中的所有注冊(cè)的監(jiān)聽(tīng)器,然后讓每個(gè)監(jiān)聽(tīng)器決定是否要處理這個(gè)事件。

我們接著到invokeListener方法中看下:

看到這里,大家應(yīng)該就明白了,最終就會(huì)調(diào)用監(jiān)聽(tīng)器中的onApplicationEvent方法執(zhí)行監(jiān)聽(tīng)器中的邏輯。

因?yàn)槟壳爸挥形覀冏远x的監(jiān)聽(tīng)器才會(huì)處理事件MyEvent,所以其他的監(jiān)聽(tīng)器就算執(zhí)行了onApplicationEvent方法,也會(huì)選擇無(wú)視這個(gè)事件。


也就是說(shuō)廣播器接收到一個(gè)事件之后,會(huì)將事件通知到所有Spring容器中的所有監(jiān)聽(tīng)器,并且調(diào)用監(jiān)聽(tīng)器中的onApplicationEvent方法來(lái)處理相應(yīng)的事件。


Spring這套基于事件驅(qū)動(dòng)的機(jī)制,相信大家現(xiàn)在應(yīng)該也比較清楚了,主要就是通過(guò)廣播器ApplicationEventMulticaster和監(jiān)聽(tīng)器ApplicationListener來(lái)實(shí)現(xiàn)的,大家也可以理解為是發(fā)布-訂閱模式,ApplicationEventMulticaster用來(lái)廣播發(fā)布事件,ApplicationListener監(jiān)聽(tīng)訂閱事件,每種監(jiān)聽(tīng)器負(fù)責(zé)處理一種或多種事件。

而且,如果大家冷靜分析一下會(huì)發(fā)現(xiàn),其實(shí)Spring這套發(fā)布訂閱的模式,采用的就是設(shè)計(jì)模式中的觀察者模式,ApplicationEventMulticaster作為廣播事件的subject,屬于被觀察者,ApplicationListener作為Observer觀察者,最終是用來(lái)處理相應(yīng)的事件的,屬于觀察者Observer。


總結(jié)


好了,今天的知識(shí)點(diǎn)我們就講到這里了,我們來(lái)總結(jié)一下吧。


第一,我們了解了Spring初始化時(shí)消息源MessageSource是如何初始化的。

第二,接下來(lái)我們又看了下Spring中的廣播器ApplicationEventMulticaster的初始化過(guò)程,默認(rèn)就是創(chuàng)建了一個(gè)SimpleApplicationEventMulticaster類型的對(duì)象。

第三,我們自定義了事件和監(jiān)聽(tīng)器,體驗(yàn)了一下如何基于Spring內(nèi)部的廣播器發(fā)布一個(gè)自定義的事件,并且通過(guò)自定義的監(jiān)聽(tīng)器來(lái)監(jiān)聽(tīng)并處理這個(gè)事件。

第四,我們分析了一下Spring源碼之后了解到Spring在發(fā)布事件時(shí),會(huì)通過(guò)Spring內(nèi)部的廣播器來(lái)遍歷所有注冊(cè)的監(jiān)聽(tīng)器,并執(zhí)行這些監(jiān)聽(tīng)器中的方法,在監(jiān)聽(tīng)器中處理這些事件。

20-Spring高級(jí)容器初始化:Spring是如何基于事件驅(qū)動(dòng)的呢?的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
遂宁市| 江陵县| 根河市| 始兴县| 永春县| 华阴市| 凯里市| 崇信县| 兴安盟| 长海县| 内黄县| 云阳县| 耿马| 秦皇岛市| 九江县| 宜昌市| 鹿泉市| 昔阳县| 永济市| 绥棱县| 聂拉木县| 新晃| 麟游县| 永胜县| 江北区| 长寿区| 上蔡县| 天全县| 钟祥市| 金乡县| 田东县| 义马市| 山阴县| 翁源县| 崇礼县| 邓州市| 洛阳市| 阜新市| 武鸣县| 太保市| 贵州省|