1. 程式人生 > >180609-Spring之事件驅動機制的簡單使用

180609-Spring之事件驅動機制的簡單使用

extend listener 支持 ati 關註 如果 ace publisher rip

技術分享圖片

文章鏈接:https://liuyueyi.github.io/hexblog/hexblog/2018/06/09/180609-Spring之事件驅動機制的簡單使用/

Spring之事件驅動機制的簡單使用

關於事件的發起與相應,在客戶端的交互中可算是非常頻繁的事情了,關於事件的發布訂閱,在Java生態中,EventBus可謂是非常有名了,而Spring也提供了事件機制,本文則主要介紹後端如何在Spring的環境中,使用事件機制

I. 使用姿勢

主要借助org.springframework.context.ApplicationEventPublisher#publishEvent(org.springframework.context.ApplicationEvent)

來發布事件,而接受方,則直接在處理的方法上,添加 @@EventListener註解即可

1. 事件定義

發布一個事件,所以第一件事就是要定義一個事件,對Spring而言,要求自定義的事件繼承自ApplicationEvent類, 一個簡單的demo如下

public class NotifyEvent extends ApplicationEvent {
    @Getter
    private String msg;

    public NotifyEvent(Object source, String msg) {
        super(source);
        this
.msg = msg; } }

2. 發布事件

發布時間則比較簡單,直接拿到ApplicationContext實例,執行publish方法即可,如下面給出一個簡單的發布類

@Component
public class NotifyPublisher implements ApplicationContextAware {
    private ApplicationContext apc;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws
BeansException { this.apc = applicationContext; } // 發布一個消息 public void publishEvent(int status, String msg) { if (status == 0) { apc.publishEvent(new NotifyEvent(this, msg)); } else { apc.publishEvent(new NewNotifyEvent(this, msg, ((int) System.currentTimeMillis() / 1000))); } } }

3. 事件監聽器

在方法上添加註解即可,如下

@Component
public class NotifyQueueListener {

    @EventListener
    public void consumerA(NotifyEvent notifyEvent) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("A: " + Thread.currentThread().getName() + " | " + notifyEvent.getMsg());
    }

    @EventListener
    public void consumerB(NewNotifyEvent notifyEvent) {
        System.out.println("B: " + Thread.currentThread().getName() + " | " + notifyEvent.getMsg());
    }


    @EventListener
    public void consumerC(NotifyEvent notifyEvent) {
        System.out.println("C: " + Thread.currentThread().getName() + " | " + notifyEvent.getMsg());
    }
}

II. 疑問及解答

1. 發布與監聽器的關聯

上面給出了使用的姿勢,看起來並不復雜,也比較容易使用,但是一個問題需要在使用之前弄明白了,發布事件和監聽器是怎麽關聯起來的呢?

  • 根據方法的參數類型執行

那麽如果發布者,推送的是一個NotifyEvent類型的事件,那麽接收者是怎樣的呢?

  • 參數為NotifyEvent以及其子類的監聽器,都可以接收到消息

測試用例如下:

NewNotifyEvent 繼承自上面的NotifyEvent

public class NewNotifyEvent extends NotifyEvent {
    @Getter
    private int version;

    public NewNotifyEvent(Object source, String msg) {
        super(source, msg);
    }
    public NewNotifyEvent(Object source, String msg, int version) {
        super(source, msg);
        this.version = version;
    }
}

然後借助上面的消息發布者發送一個消息

@Test
public void testPublishEvent() throws InterruptedException {
    notifyPublisher.publishEvent(1, "新的發布事件! NewNotify");
    System.out.println("---------");
    notifyPublisher.publishEvent(0, "舊的發布事件! Notify");
}

輸出結果如下,對於NewNotifyEvent, 參數類型為NotifyEvent的consumerA, consumerC都可以接收到

A: main | 新的發布事件! NewNotify
C: main | 新的發布事件! NewNotify
B: main | 新的發布事件! NewNotify
---------
A: main | 舊的發布事件! Notify
C: main | 舊的發布事件! Notify

2. 消息接收的順序

上面消息處理是串行的,那麽先後順序怎麽確定? (下面的答案不確定,有待深入源碼驗證!!!)

  • 先掃描到的bean先處理
  • 同一個bean中,按精確匹配,先後定義順序進行

3. 異步消費

對於異步消費,即在消費者方法上添加一個@Async註解,並需要在配置文件中,開啟異步支持

@Async
@EventListener
public void processNewNotifyEvent(NewNotifyEvent newNotifyEvent) {
    System.out.println("new notifyevent: " + newNotifyEvent.getMsg() + " : " + newNotifyEvent.getVersion());
}

配置支持

@Configuration
@EnableAsync
public class AysncListenerConfig implements AsyncConfigurer {
    /**
     * 獲取異步線程池執行對象
     *
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        return new ThreadPoolExecutor(5, 10, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>(),
                new DefaultThreadFactory("test"), new ThreadPoolExecutor.CallerRunsPolicy());
    }
}

III. 其他

一灰灰Blog: https://liuyueyi.github.io/hexblog

一灰灰的個人博客,記錄所有學習和工作中的博文,歡迎大家前去逛逛

聲明

盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

  • 微博地址: 小灰灰Blog
  • QQ: 一灰灰/3302797840

掃描關註

技術分享圖片

180609-Spring之事件驅動機制的簡單使用