spring 事件機(jī)制

??在軟件開發(fā)過程中,有時(shí)候我們會(huì)遇到需要把具體業(yè)務(wù)解耦出來美莫,讓各個(gè)模塊只負(fù)責(zé)相應(yīng)的處理邏輯.比如說菜拓,在我們的抽象業(yè)務(wù)邏輯中有一個(gè)負(fù)責(zé)開往目的地的司機(jī)driver,現(xiàn)在我們的業(yè)務(wù)系統(tǒng)中不僅要處理司機(jī)去往目的地的邏輯系宫,也有其他業(yè)務(wù)模塊需要關(guān)注司機(jī)具體的目的地是什么地方索昂。然而司機(jī)只負(fù)責(zé)把乘客送到具體地方。不需要負(fù)責(zé)告訴業(yè)務(wù)他去哪里扩借。這時(shí)候我們可以采用spring的事件機(jī)制椒惨,讓業(yè)務(wù)解耦。

spring的事件機(jī)制包括:

事件源潮罪,對(duì)應(yīng)具體的事件康谆。
事件監(jiān)聽器,負(fù)責(zé)接收具體的事件源嫉到。
事件廣播器沃暗, 負(fù)責(zé)發(fā)布事件源。

??相應(yīng)的處理邏輯為:事件監(jiān)聽器會(huì)注冊(cè)具體的事件源何恶,當(dāng)事件廣播器廣播具體的事件源后孽锥,事件監(jiān)聽器能接到該事件的發(fā)布消息,然后處理相關(guān)事件导而。

事件源

??定義事件源需要繼承spring的ApplicationEvent類忱叭,該類有兩子類ApplicationContextEvent,RequestHandledEvent.
??ApplicationContextEvent有4個(gè)子類今艺,ContextStartedEvent韵丑,ContextRefreshedEvent,ContextClosedEvent虚缎,ContextStoppedEvent撵彻,分別表示容器啟動(dòng)钓株,刷新,關(guān)閉陌僵,停止的事件轴合。
??RequestHandledEvent只有定義了DispatcherServlet時(shí)才會(huì)產(chǎn)生該事件,它的子類ServletRequestHandledEvent代表Servlet請(qǐng)求事件碗短。
??這里選擇定義一個(gè)司機(jī)行駛的事件類:DriverEvent受葛,它繼承于ApplicationContextEvent。它有一個(gè)目的地屬性destination偎谁,然后這里需要實(shí)現(xiàn)它的構(gòu)造函數(shù)总滩,提供一個(gè)spring的上下文。

package spring;

import lombok.Data;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;

@Data
public class DriveEvent extends ApplicationContextEvent {

    private String destination;
    public DriveEvent(ApplicationContext source, String destination) {
        super(source);
        this.destination = destination;
    }
}

事件監(jiān)聽器

??定于事件監(jiān)聽器需要實(shí)現(xiàn)ApplicationListener接口巡雨,我們定義一個(gè)DriveEventListener事件監(jiān)聽器闰渔,通過泛型注冊(cè)了它關(guān)注的事件DriveEvent,然后實(shí)現(xiàn)接口的onApplicationEvent(DriveEvent event)铐望,這里我們把事件的目的地打印出來冈涧。

package spring;

import org.springframework.context.ApplicationListener;

public class DriveEventListener implements ApplicationListener<DriveEvent> {
    @Override
    public void onApplicationEvent(DriveEvent event) {
        System.out.println("本次哈哈列車開往目的地:" + event.getDestination());
    }
}

事件廣播器

??接下來就需要定義事件廣播器了,事件的廣播器其實(shí)是通過spring的上下文ApplicationContext調(diào)用它的publishEvent(ApplicationEvent event)方法的正蛙,參數(shù)就是具體的繼承于ApplicationEvent的事件源督弓,這里我們定義一個(gè)Driver類,該類負(fù)責(zé)具體驅(qū)車前往目的地乒验,然后發(fā)布一個(gè)DriveEvent咽筋。

package spring;

import org.springframework.context.ApplicationContext;

public class Driver {
    private ApplicationContext applicationContext = SpingContextHolder.getApplicationContext();
    
public void drive(String destionation) {
        System.out.println("司機(jī)開車前往目的地");
        DriveEvent driveEvent = new DriveEvent(applicationContext, destionation);
        applicationContext.publishEvent(driveEvent);
    }
}

??這里可以看到Driver有一個(gè)drive(String desctination)方法,它負(fù)責(zé)具體的驅(qū)車邏輯徊件,然后他會(huì)通過springcontext發(fā)布一個(gè)驅(qū)車事件,出于方便蒜危,我們?cè)俣x一個(gè)SpingContextHolder來獲取spring的上下文虱痕。
??在程序中獲取spring上下文可以通過指定具體的xml文件,也可以通過實(shí)現(xiàn)ApplicationContextAware 接口辐赞,然后實(shí)現(xiàn)它的setApplicationContext(ApplicationContext ctx)方法部翘,spring會(huì)傳遞當(dāng)先程序的上下文,我們給該類定義一個(gè)靜態(tài)的上下文變量context响委,把spring的上下文分配給它新思。代碼如下:

package spring;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpingContextHolder implements ApplicationContextAware {
    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        context = ctx;
    }

    public static ApplicationContext getApplicationContext(){
        return context;
    }
}

啟動(dòng)類

??現(xiàn)在相應(yīng)的事件機(jī)制組件都已經(jīng)定義好了,我們這里再定義一個(gè)啟動(dòng)類赘风。
??啟動(dòng)類的邏輯流程為:我們?cè)趕pring的配置文件context.xml中裝配一個(gè)司機(jī)組件driver夹囚;程序啟動(dòng),通過ClassPathXmlApplicationContext來獲取司機(jī)的bean邀窃,司機(jī)driver調(diào)用drive方法驅(qū)車前往目的地荸哟。這時(shí)候自己的drive方法會(huì)發(fā)布DriveEvent事件,DriveEventListner會(huì)監(jiān)聽到然后打印出司機(jī)前往的目的地。這里司機(jī)只是在drive方法中發(fā)布一個(gè)驅(qū)車事件鞍历,然后驅(qū)車前往目的地舵抹,具體的處理邏輯通過事件機(jī)制交給了監(jiān)聽器處理邏輯,達(dá)到了程序解耦的效果劣砍。

package spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-context.xml");
        Driver driver = (Driver) applicationContext.getBean("driver");
        driver.drive("上海浦東");
    }
}

spring配置文件:

   <bean id="spingContextHolder" class="spring.SpingContextHolder"/>
   <bean id="driver" class="spring.Driver"/>
   <bean id="driveListener" class="spring.DriveEventListener"/>

總結(jié)

??我們通過繼承ApplicationEvent類來定義具體的事件惧蛹,然后實(shí)現(xiàn)ApplicationListener來注冊(cè)具體的事件以及相應(yīng)的處理邏輯,事件的廣播是通過spring的上下文ApplicationContext調(diào)用它的publishEvent(ApplicationEvent event)方法來實(shí)現(xiàn)的刑枝。當(dāng)事件廣播器廣播具體的事件源后香嗓,事件監(jiān)聽器能接到該事件的發(fā)布消息,然后處理相關(guān)事件仅讽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陶缺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子洁灵,更是在濱河造成了極大的恐慌饱岸,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徽千,死亡現(xiàn)場(chǎng)離奇詭異苫费,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)双抽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門百框,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牍汹,你說我怎么就攤上這事铐维。” “怎么了慎菲?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵嫁蛇,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我露该,道長(zhǎng)睬棚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任解幼,我火速辦了婚禮抑党,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘撵摆。我一直安慰自己底靠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布台汇。 她就那樣靜靜地躺著苛骨,像睡著了一般篱瞎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上痒芝,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天俐筋,我揣著相機(jī)與錄音,去河邊找鬼严衬。 笑死澄者,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的请琳。 我是一名探鬼主播粱挡,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼俄精!你這毒婦竟也來了询筏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤竖慧,失蹤者是張志新(化名)和其女友劉穎嫌套,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體圾旨,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡踱讨,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了砍的。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痹筛。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖廓鞠,靈堂內(nèi)的尸體忽然破棺而出帚稠,到底是詐尸還是另有隱情,我是刑警寧澤床佳,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布翁锡,位于F島的核電站,受9級(jí)特大地震影響夕土,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瘟判,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一怨绣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拷获,春花似錦篮撑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)未蝌。三九已至,卻和暖如春茧妒,著一層夾襖步出監(jiān)牢的瞬間萧吠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工桐筏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纸型,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓梅忌,卻偏偏與公主長(zhǎng)得像狰腌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子牧氮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359