一步一步教你使用Spring框架中的事件訂閱發佈

1. 前言

Java 開發中有些邏輯是這樣的,完成了A操做,再繼續B操做,在繼續C操做。這麼描述好像有點不清楚。打個比方把,你吃晚飯,通知你老婆(女朋友)來收碗筷,而後通知你的線上兄弟告訴他們你回來了準備開黑。至於你老婆(女朋友)來不來收拾無所謂,反正你告訴她了。至於你兄弟你也是通知他們,人家也不必定組你,萬一他們正在跟一個一拖三的carry大佬玩的正起勁兒呢。java

2. 事件的概念

吃晚飯就是一個所謂的事件。觸發了隨後的兩個操做,他們只存在因果關係。可是它們互不干擾,各自爲政。一個完整的事件由 事件源、事件發佈、事件監聽 組成。 接下來咱們聊聊 Spring 中的事件。git

3. Spring 中的事件

Spring 框架中使用了大量的事件機制,好比 Spring Boot 的啓動。方便起見咱們新建一個 Spring Boot 工程。而後跟着我一步步的來進行事件的操做。spring

3.1 聲明事件

  • 聲明一個事件。經過繼承 org.springframework.context.ApplicationEvent 來編寫事件。時間裏定義好事件推送到監聽器須要執行的方法,固然也能夠在監聽器裏寫觸發邏輯。咱們來聲明一下:
package cn.felord.boot.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

/**
 * 吃飯事件
 *
 * @author dax
 * @since 2019 /7/8 21:54
 */
@Slf4j
public class EatEvent extends ApplicationEvent {
    private Boolean eatFinished;


    /**
     * Instantiates a new Eat event.
     *
     * @param eatFinished 吃飯是否完成的信號 這裏也能夠傳遞其餘資源
     */
    public EatEvent(Boolean eatFinished) {
        super(eatFinished);
        this.eatFinished = eatFinished;
    }

    /**
     * 這裏會由對應監聽器{@link ApplicationListener<EatEvent>} 執行
     *
     * 叫女朋友收拾碗筷.
     */
    public void callGirlFriend() {
        log.info("親愛的! 我吃完飯了,來收拾收拾吧");
    }

    /**
     * 這裏會由對應監聽器{@link ApplicationListener<EatEvent>} 執行
     * 呼叫兄弟開黑.
     */
    public void callBrothers() {
        log.info("兄弟們! 我吃完飯了,帶我開黑");
    }

    /**
     * 吃晚飯的信號.
     *
     * @return the boolean
     */
    public Boolean isEatFinished() {
        return this.eatFinished;
    }
}

3.2 事件發佈

發佈事件經過實現事件發佈接口 org.springframework.context.ApplicationEventPublisher 或者其門面接口 org.springframework.context.ApplicationEventPublisherAware, 推薦門面接口,裏面要定義一個主動推送事件的方法以下面的 refreshEvent 方法,實際代理了 ApplicationEventPublisher 執行其 publishEvent 方法:segmentfault

package cn.felord.boot.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

/**
 * 發佈事件 發佈事件經過實現 事件發佈接口 {@link ApplicationEventPublisher}
 * 或者經過門面接口{@link ApplicationEventPublisherAware}
 * 推薦按照下面的實現方式,並且該類須要註冊爲spring bean
 *
 * @author dax
 * @since 2019 /7/8 22:04
 */
@Slf4j
public class EatEventPublisherAware implements ApplicationEventPublisherAware {
    private ApplicationEventPublisher applicationEventPublisher;

    private ApplicationEvent eatEvent;

    public EatEventPublisherAware(ApplicationEvent eatEvent) {
        this.eatEvent = eatEvent;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    /**
     * 發送事件動做   事件的動做須要主動觸發  調用此方法進行事件觸發
     * 代理{@link ApplicationEventPublisher#publishEvent(ApplicationEvent)}
     */
    public void refreshEvent() {
        log.info("發送事件中……");
        this.applicationEventPublisher.publishEvent(eatEvent);
    }

}

3.3 事件監聽

事件監聽用來監聽事件以觸發相關的邏輯。經過實現 org.springframework.context.ApplicationListener<E extends ApplicationEvent> 來實現事件的監聽。特別注意泛型E,若是不指定事件將能夠接收任何事件,儘可能職責單一。app

package cn.felord.boot.event;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;

/**
 * {@link EatEvent}事件的專屬事件監聽器
 * @author dax
 * @since 2019/7/8 22:11
 */
@Slf4j
public class EatEventListener implements ApplicationListener<EatEvent> {
    @Override
    public void onApplicationEvent(EatEvent eatEvent) {
        //若是吃完飯了
        if (eatEvent.isEatFinished()) {
            eatEvent.callGirlFriend();
            log.error("來自母老虎的咆哮:滾犢子");
            eatEvent.callBrothers();
            log.error("太晚了,咱們已經滿了,明天帶你");
            log.info("仍是關注一下 【碼農小胖哥】 學習點新知識吧");
        }
    }
}

3.4 注入Spring IoC

將上面三個類注入 Spring 容器中,這裏咱們採用了 JavaConfig 方式,看起來更明顯。框架

package cn.felord.boot.config;

import cn.felord.boot.event.EatEvent;
import cn.felord.boot.event.EatEventListener;
import cn.felord.boot.event.EatEventPublisherAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 這三個必定要配置成bean
 *
 * @author dax
 * @since 2019/7/8 22:16
 */
@Configuration
public class EventConfig {

    @Bean
    public ApplicationEvent eatEvent() {
        return new EatEvent(true);
    }

    @Bean
    public ApplicationListener eatEventListener() {
        return new EatEventListener();
    }

    @Bean
    public ApplicationEventPublisherAware eatEventPublisherAware(ApplicationEvent eatEvent) {
        return new EatEventPublisherAware(eatEvent);
    }

}

4. 測試

這裏就大功告成了,那麼如何使用呢,執行事件發佈器的發佈方法 refreshEvent 就好了,事件監聽器監聽到事件會自動響應。咱們來寫一個單元測試。ide

package cn.felord.boot;

import cn.felord.boot.event.EatEventPublisherAware;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

@RunWith(SpringRunner.class)
@SpringBootTest
public class EventSpringApplicationTests {
@Resource
private EatEventPublisherAware eatEventPublisherAware;
    @Test
    public void contextLoads() {

        eatEventPublisherAware.refreshEvent();
    }

}

運行一下,入圖單元測試

到此你應該就學會使用 Spring 事件了,這樣寫出來的代碼逼格更高。還能提現你對 Spring 框架的一些理解。固然還有一種更加簡單的、基於註解的方式,這裏再也不闡述。相關代碼在個人 碼雲倉庫學習

關注公衆號:Felordcn 獲取更多資訊測試

我的博客:https://felord.cn

相關文章
相關標籤/搜索