Spring事件機(jī)制

1. 使用Spring 事件

首先spring事件分為事件發(fā)布者(EventPublisher)、事件監(jiān)聽者(EventListener),還包括一個(gè)事件廣播者(這個(gè)是spring實(shí)現(xiàn)相關(guān),這一節(jié)不討論)。使用spring事件機(jī)制,需要自定義事件發(fā)布者和監(jiān)聽者。
以一個(gè)簡單的例子開始,事件發(fā)布者發(fā)送一個(gè)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);
    }
}

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

關(guān)于ApplicationEventPublisherAware如下:

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

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

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

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

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

2. Spring事件原理

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

Spring事件機(jī)制

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

2.1 EventMultiCaster

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

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        //判斷有沒有一個(gè)name是“applicationEventMulticaster”且實(shí)現(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 {
            // 沒有這樣一個(gè)bean,那就會(huì)創(chuàng)建一個(gè)默認(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) {
                // 這個(gè)是用來根據(jù)event的類型找到合適的listener的
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
                        
            Executor executor = getTaskExecutor();
            // executor不是空的時(shí)候會(huì)在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時(shí),executor是null,所以默認(rèn)情況下所有的listener 的onApplicationEvent是直接在當(dāng)前線程(事件發(fā)布者所在線程)中調(diào)用,所以
如果onApplicationEvent有阻塞操作也會(huì)導(dǎo)致事件發(fā)布者被阻塞,后續(xù)的其他listener也會(huì)被阻塞無法調(diào)用。

  1. 自定義multicaster
    「2.1」中介紹spring會(huì)加載一個(gè)叫applicationEventMulticaster且實(shí)現(xiàn)了ApplicationEventMulticaster接口的multicaster,自定義multicaster需要實(shí)現(xiàn)了該接口然后將bean的名字設(shè)為applicationEventMulticaster即可。
    下面的例子為默認(rèn)的SimpleApplicationEventMulticaster添加了executor,以使事件發(fā)布者和監(jiān)聽者不用在同一個(gè)線程中調(diào)用:
//使用線程池運(yùn)行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啟動(dòng)完成之后(已經(jīng)完成bean解析,non-lazy-init的singleton實(shí)例化和初始化,完成listener的注冊),默認(rèn)會(huì)發(fā)布一個(gè)ContextRefreshedEvent事件,該事件包裝的消息是一個(gè)ApplicationContext對象。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

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

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