SpringBoot--開發(fā)實(shí)戰(zhàn)--監(jiān)聽器(四十一)

一咏连、ApplicationListener

ApplicationContext提供事件處理通過ApplicationEvent類和ApplicationListener接口。如果一個(gè)bean實(shí)現(xiàn)ApplicationListener接口在容器中,每次一個(gè)ApplicationEvent被發(fā)布到ApplicationContext中,這類bean就會(huì)收到這些通知币砂。
實(shí)現(xiàn)Spring事件機(jī)制主要有4個(gè)類:
ApplicationEvent:事件,每個(gè)實(shí)現(xiàn)類表示一類事件攒发,可攜帶數(shù)據(jù)有滑。
ApplicationListener:事件監(jiān)聽器,用于接收事件處理時(shí)間壹士。
ApplicationEventMulticaster:事件管理者磷雇,用于事件監(jiān)聽器的注冊(cè)和事件的廣播。
ApplicationEventPublisher:事件發(fā)布者躏救,委托ApplicationEventMulticaster完成事件發(fā)布唯笙。

  1. 事件就是一個(gè)包含了任意對(duì)象并含有事件對(duì)象創(chuàng)建時(shí)間戳的類。
    框架源碼:
public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;
    private final long timestamp = System.currentTimeMillis();

    public ApplicationEvent(Object source) {
        super(source);
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}
  1. ApplicationListener
    框架源碼:
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    void onApplicationEvent(E var1);
}

當(dāng)事件監(jiān)聽器接收到它可以處理的事件盒使,會(huì)調(diào)用onApplicationEvent()方法崩掘。注意到ApplicationListener是泛型參數(shù)的這樣可以參數(shù)化的定制事件。這意味著onApplicationEvent()方法可以保持類型安全,避免任何需要向下類型轉(zhuǎn)換少办。你可以盡可能多的注冊(cè)你希望事件偵聽器,但是注意,默認(rèn)情況下,事件監(jiān)聽器同步接收事件苞慢。這意味著publishEvent()方法會(huì)阻塞直到所有的事件監(jiān)聽器成處理完事件。這種單線程同步方法的一個(gè)特點(diǎn)是,當(dāng)一個(gè)監(jiān)聽器接收到一個(gè)事件時(shí),它運(yùn)行在事務(wù)上下文的發(fā)布者線程上如果事務(wù)上下文可用英妓。如果事件的發(fā)布需要另一種策略(譬如多線程)需要實(shí)現(xiàn)自己的 ApplicationEventMulticaster接口類挽放。

  1. ApplicationEventMulticaster
    ApplicationEventMulticaster接口方法分為三類,注冊(cè)事件監(jiān)聽器蔓纠、移除事件監(jiān)聽器辑畦、發(fā)布事件。

二腿倚、Spring內(nèi)置事件

事件 描述
ContextRefreshedEvent 事件發(fā)布在ApplicationContext初始化或刷新時(shí)(例如,通過在ConfigurableApplicationContext接口使用refresh()方法)纯出。這里,“初始化”意味著所有bean加載,post-processor bean被檢測(cè)到并且激活,單例預(yù)先實(shí)例化,ApplicationContext對(duì)象可以使用了。只要上下文沒有關(guān)閉,可以觸發(fā)多次刷新,ApplicationContext提供了一種可選擇的支持這種“熱”刷新猴誊。例如,XmlWebApplicationContext支持熱刷新,但GenericApplicationContext并非如此潦刃。具體是在AbstractApplicationContext的finishRefresh()方法中。
ContextStartedEvent 事件發(fā)布在ApplicationContext開始使用ConfigurableApplicationContext接口start()方法懈叹。這里,“開始”意味著所有生命周期bean接收到一個(gè)明確的起始信號(hào)乖杠。通常,這個(gè)信號(hào)用于明確停止后重新啟動(dòng),但它也可以用于啟動(dòng)組件沒有被配置為自動(dòng)運(yùn)行(例如,組件還沒有開始初始化)。
ContextStoppedEvent 事件發(fā)布在ApplicationContext停止時(shí)通過使用ConfigurableApplicationContext接口上的stop()方法澄成。在這里,“停止”意味著所有生命周期bean接收一個(gè)顯式的停止信號(hào)胧洒。停止上下文可以通過重新調(diào)用start()方法畏吓。
ContextClosedEvent 事件發(fā)布在ApplicationContext關(guān)閉時(shí)通過關(guān)閉ConfigurableApplicationContext接口()方法。這里,“封閉”意味著所有單例bean被摧毀卫漫。一個(gè)封閉的環(huán)境達(dá)到生命的終結(jié)菲饼。它不能刷新或重啟。
RequestHandledEvent 一個(gè)特定的web事件告訴所有能處理HTTP請(qǐng)求的bean 列赎。這個(gè)事件是在請(qǐng)求完成后發(fā)布的宏悦。這個(gè)事件只適用于使用Spring的DispatcherServlet的web應(yīng)用程序。

三包吝、示例

當(dāng)一個(gè)用戶完成貸款訂單后饼煞,我們希望執(zhí)行發(fā)送提醒短信、調(diào)用積分服務(wù)增加積分诗越、通知風(fēng)控服務(wù)重算風(fēng)控值(后續(xù)操作可能增加)等功能砖瞧。

//創(chuàng)建訂單
public void createOrder(Order order){
創(chuàng)建貸款訂單;
發(fā)送提醒短信嚷狞;
調(diào)用積分服務(wù)增加積分块促;
調(diào)用風(fēng)控服務(wù)推送訂單信息;
……
返回床未;
}

隨著業(yè)務(wù)復(fù)雜度的增加竭翠,我們很快發(fā)現(xiàn)createOrder()創(chuàng)建訂單這個(gè)方法耦合了太多與注冊(cè)無關(guān)的邏輯,即影響了原本創(chuàng)建訂單方法的效率即硼,在設(shè)計(jì)上又不符合“開閉原則”逃片。
現(xiàn)在使用spring事件機(jī)制我們來解耦屡拨,將與注冊(cè)無關(guān)的操作改為異步只酥。這里直接使用注解式寫法。

  1. 創(chuàng)建訂單實(shí)體
@Data
@Component
public class Order {
    private String orderNo;
    private String phone;
}
  1. 創(chuàng)建事件
/**
 * 創(chuàng)建訂單完成事件
 */
@Component
public class AfterCreateOrderEvent extends ApplicationEvent {
    public AfterCreateOrderEvent(Order order) {
        super(order);
    }
    public Order getOrder(){
        return (Order) getSource();
    }
}
  1. 創(chuàng)建業(yè)務(wù)類進(jìn)行事件發(fā)布與監(jiān)聽
@Service
public class OrderService {
    //直接注入spring事件發(fā)布者
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    /**
     * 簡(jiǎn)單的創(chuàng)建訂單方法
     */
    public void createOrder(Order order) {
        System.out.println("創(chuàng)建訂單 order:" + order.getOrderNo() + " 結(jié)束");
        // TODO 1. 調(diào)用事件發(fā)布者發(fā)布事件,解耦
        applicationEventPublisher.publishEvent(new AfterCreateOrderEvent(order));
        System.out.println("createOrder方法 結(jié)束");
    }

    // TODO 2. 事件監(jiān)聽處理呀狼,加入@EventListener注解后裂允,該方法可以看出一個(gè)事件監(jiān)聽者
    @EventListener
    public void afterCreateOrder(AfterCreateOrderEvent afterCreateOrderEvent) throws InterruptedException {
        Order order = afterCreateOrderEvent.getOrder();
        Thread.sleep(2000);
        System.out.println("調(diào)用短信通知服務(wù):" + order.getPhone());
        System.out.println("調(diào)用積分服務(wù)增加貸款積分:" + order.getOrderNo());
    }
}
  1. 測(cè)試
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringSessionApplicationTests {
    @Autowired
    private OrderService orderService;

    @Test
    public void eventTest() {
        Order order = new Order();
        order.setOrderNo("N123124124124");
        order.setPhone("18782202534");
        orderService.createOrder(order);
    }
}
結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哥艇,隨后出現(xiàn)的幾起案子绝编,更是在濱河造成了極大的恐慌,老刑警劉巖貌踏,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件十饥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡祖乳,警方通過查閱死者的電腦和手機(jī)逗堵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眷昆,“玉大人蜒秤,你說我怎么就攤上這事汁咏。” “怎么了作媚?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵攘滩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我纸泡,道長(zhǎng)漂问,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任女揭,我火速辦了婚禮级解,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘田绑。我一直安慰自己勤哗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布掩驱。 她就那樣靜靜地躺著芒划,像睡著了一般。 火紅的嫁衣襯著肌膚如雪欧穴。 梳的紋絲不亂的頭發(fā)上民逼,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音涮帘,去河邊找鬼拼苍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛调缨,可吹牛的內(nèi)容都是我干的疮鲫。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼弦叶,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼俊犯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伤哺,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤燕侠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后立莉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绢彤,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年蜓耻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茫舶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡媒熊,死狀恐怖奇适,靈堂內(nèi)的尸體忽然破棺而出坟比,到底是詐尸還是另有隱情,我是刑警寧澤嚷往,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布葛账,位于F島的核電站,受9級(jí)特大地震影響皮仁,放射性物質(zhì)發(fā)生泄漏籍琳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一贷祈、第九天 我趴在偏房一處隱蔽的房頂上張望趋急。 院中可真熱鬧,春花似錦势誊、人聲如沸呜达。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽查近。三九已至,卻和暖如春挤忙,著一層夾襖步出監(jiān)牢的瞬間霜威,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國打工册烈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戈泼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓赏僧,卻偏偏與公主長(zhǎng)得像大猛,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子次哈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容