Spring事件機制

1. 使用Spring 事件

首先spring事件分為事件發(fā)布者(EventPublisher)、事件監(jiān)聽者(EventListener),還包括一個事件廣播者(這個是spring實現(xiàn)相關(guān),這一節(jié)不討論)。使用spring事件機制,需要自定義事件發(fā)布者和監(jiān)聽者。
以一個簡單的例子開始,事件發(fā)布者發(fā)送一個string類型的消息,接受者將接收到的消息打印出來。

  1. 事件發(fā)布者
@Component
public class SaySomethingPublisher implements ApplicationEventPublisherAware{
    private ApplicationEventPublisher applicationEventPublisher;

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

    public void saySomething(String msg){
        applicationEventPublisher.publishEvent(msg);
    }
}

需要實現(xiàn)ApplicationEventPublisherAware這個Aware接口,廣播事件需要利用applicationEventPublisher

關(guān)于ApplicationEventPublisherAware如下:

public interface ApplicationEventPublisher {
    void publishEvent(ApplicationEvent event);
    void publishEvent(Object event);
}

用戶發(fā)布的事件類型可以是:
1. 用戶可以繼承ApplicationEvent從而自定義Event類型
2. 也可以使用任意Object類型,但是如果event真實類型不是ApplicationEvent的話,那么event會被封裝成PayloadApplicationEvent
  1. 事件監(jiān)聽者

//事件監(jiān)聽者需要實現(xiàn)ApplicationListener接口
@Component
public class ListenerA implements ApplicationListener<PayloadApplicationEvent<String>> {
    // 由于監(jiān)聽的是String類型的事件會被封裝成PayloadApplicationEvent,所以此處類型是PayloadApplicationEvent
    public void onApplicationEvent(PayloadApplicationEvent event) {
        // getSource返回真實的事件
        Object msg = event.getSource();
        System.out.println("ListenerA receive:" + msg);
    }
}

關(guān)于發(fā)布出去的事件,那些監(jiān)聽者會監(jiān)聽到?

  1. 發(fā)布的事件類型是ApplicationEvent的實現(xiàn)類A
    那么所有監(jiān)聽者的onApplicationEvent的參數(shù)類型是A或者A的子類都會收到事件。
  2. 發(fā)布的事件類型是不是ApplicationEvent類型,類型是B
    這種情況下,最終事件會被包裝成PayloadApplicationEvent<B>, 那么所有監(jiān)聽者方法onApplicationEvent的參數(shù)是PayloadApplicationEvent<B>的監(jiān)聽者會收到, 假設(shè)有C是B的父類,且有一個監(jiān)聽者X監(jiān)聽PayloadApplicationEvent<C>,那X是收不到PayloadApplicationEvent<B>類型的事件的

2. Spring事件原理

Spring事件機制是觀察者模式的一種實現(xiàn),但是除了發(fā)布者和監(jiān)聽者者兩個角色之外,還有一個EventMultiCaster的角色負(fù)責(zé)把事件轉(zhuǎn)發(fā)給監(jiān)聽者,工作流程如下:

Spring事件機制

也就是說上面代碼中發(fā)布者調(diào)用applicationEventPublisher.publishEvent(msg); 是會將事件發(fā)送給了EventMultiCaster, 而后由EventMultiCaster注冊著所有的Listener,然后根據(jù)事件類型決定轉(zhuǎn)發(fā)給那個Listener。

2.1 EventMultiCaster

ApplicationContext完成bean的裝配和初始化后(非lazy-init的singleton bean會加載后就初始化),會嘗試創(chuàng)建一個eventMultiCaster,創(chuàng)建代碼如下:

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //判斷有沒有一個name是“applicationEventMulticaster”且實現(xiàn)了“ ApplicationEventMulticaster”的bean,有的話那它就是eventMultiCaster
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isDebugEnabled()) {
                logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            // 沒有這樣一個bean,那就會創(chuàng)建一個默認(rèn)的
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isDebugEnabled()) {
                logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                        APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                        "': using default [" + this.applicationEventMulticaster + "]");
            }
        }
}
  1. 默認(rèn)SimpleApplicationEventMulticaster
    直接看一下SimpleApplicationEventMulticaster用來廣播event的代碼:
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
                // 這個是用來根據(jù)event的類型找到合適的listener的
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
                        
            Executor executor = getTaskExecutor();
            // executor不是空的時候會在executor中激活listener
            if (executor != null) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        invokeListener(listener, event);
                    }
                });
            }
            // 否則就直接在當(dāng)前調(diào)用線程中激活listener 
            else {
                invokeListener(listener, event);
            }
        }
}

在創(chuàng)建SimpleApplicationEventMulticaster時,executor是null,所以默認(rèn)情況下所有的listener 的onApplicationEvent是直接在當(dāng)前線程(事件發(fā)布者所在線程)中調(diào)用,所以
如果onApplicationEvent有阻塞操作也會導(dǎo)致事件發(fā)布者被阻塞,后續(xù)的其他listener也會被阻塞無法調(diào)用。

  1. 自定義multicaster
    「2.1」中介紹spring會加載一個叫applicationEventMulticaster且實現(xiàn)了ApplicationEventMulticaster接口的multicaster,自定義multicaster需要實現(xiàn)了該接口然后將bean的名字設(shè)為applicationEventMulticaster即可。
    下面的例子為默認(rèn)的SimpleApplicationEventMulticaster添加了executor,以使事件發(fā)布者和監(jiān)聽者不用在同一個線程中調(diào)用:
//使用線程池運行l(wèi)istener
<bean id="executorService" class="java.util.concurrent.Executors" factory-method="newCachedThreadPool">
 </bean>

<bean id="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
       <property name="taskExecutor" ref="executorService">
       </property>
</bean>

3. 附

  1. Spring啟動完成之后(已經(jīng)完成bean解析,non-lazy-init的singleton實例化和初始化,完成listener的注冊),默認(rèn)會發(fā)布一個ContextRefreshedEvent事件,該事件包裝的消息是一個ApplicationContext對象。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,290評論 6 342
  • 什么是Spring Spring是一個開源的Java EE開發(fā)框架。Spring框架的核心功能可以應(yīng)用在任何Jav...
    jemmm閱讀 16,785評論 1 133
  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風(fēng)情閱讀 1,861評論 0 3
  • application的配置屬性。 這些屬性是否生效取決于對應(yīng)的組件是否聲明為Spring應(yīng)用程序上下文里的Bea...
    新簽名閱讀 5,545評論 1 27

友情鏈接更多精彩內(nèi)容