Spring ApplicationContext事件機(jī)制

ApplicationContext中事件處理是由ApplicationEvent類和ApplicationListener接口來提供的。如果一個(gè)Bean實(shí)現(xiàn)了ApplicationListener接口,并且已經(jīng)發(fā)布到容器中去,每次ApplicationContext發(fā)布一個(gè)ApplicationEvent事件,這個(gè)Bean就會(huì)接到通知。Spring事件機(jī)制是觀察者模式的實(shí)現(xiàn)。

Spring中提供的標(biāo)準(zhǔn)事件:

  • ContextRefreshEvent,當(dāng)ApplicationContext容器初始化完成或者被刷新的時(shí)候,就會(huì)發(fā)布該事件。比如調(diào)用ConfigurableApplicationContext接口中的refresh()方法。此處的容器初始化指的是所有的Bean都被成功裝載,后處理(post-processor)Bean被檢測(cè)到并且激活,所有單例Bean都被預(yù)實(shí)例化,ApplicationContext容器已經(jīng)可以使用。只要上下文沒有被關(guān)閉,刷新可以被多次觸發(fā)。XMLWebApplicationContext支持熱刷新,GenericApplicationContext不支持熱刷新。

  • ContextStartedEvent,當(dāng)ApplicationContext啟動(dòng)的時(shí)候發(fā)布事件,即調(diào)用ConfigurableApplicationContext接口的start方法的時(shí)候。這里的啟動(dòng)是指,所有的被容器管理生命周期的Bean接受到一個(gè)明確的啟動(dòng)信號(hào)。在經(jīng)常需要停止后重新啟動(dòng)的場(chǎng)合比較適用。

  • ContextStoppedEvent,當(dāng)ApplicationContext容器停止的時(shí)候發(fā)布事件,即調(diào)用ConfigurableApplicationContext的close方法的時(shí)候。這里的停止是指,所有被容器管理生命周期的Bean接到一個(gè)明確的停止信號(hào)。

  • ContextClosedEvent,當(dāng)ApplicationContext關(guān)閉的時(shí)候發(fā)布事件,即調(diào)用ConfigurableApplicationContext的close方法的時(shí)候,關(guān)閉指的是所有的單例Bean都被銷毀。關(guān)閉上下后,不能重新刷新或者重新啟動(dòng)。

  • RequestHandledEvent,只能用于DispatcherServlet的web應(yīng)用,Spring處理用戶請(qǐng)求結(jié)束后,系統(tǒng)會(huì)觸發(fā)該事件。

實(shí)現(xiàn)

ApplicationEvent,容器事件,必須被ApplicationContext發(fā)布。

ApplicationListener,監(jiān)聽器,可由容器中任何監(jiān)聽器Bean擔(dān)任。

實(shí)現(xiàn)了ApplicationListener接口之后,需要實(shí)現(xiàn)方法onApplicationEvent(),在容器將所有的Bean都初始化完成之后,就會(huì)執(zhí)行該方法。

觀察者模式

觀察者模式,Observer Pattern也叫作發(fā)布訂閱模式Publish/Subscribe。定義對(duì)象間一對(duì)多的依賴關(guān)系,使得每當(dāng)一個(gè)對(duì)象改變狀態(tài),則所有依賴與它的對(duì)象都會(huì)得到通知,并被自動(dòng)更新。

觀察者模式的幾角色名稱:

  • Subject被觀察者,定義被觀察者必須實(shí)現(xiàn)的職責(zé),它能動(dòng)態(tài)的增加取消觀察者,它一般是抽象類或者是實(shí)現(xiàn)類,僅僅完成作為被觀察者必須實(shí)現(xiàn)的職責(zé):管理觀察者并通知觀察者。
  • Observer觀察者,觀察者接受到消息后,即進(jìn)行更新操作,對(duì)接收到的信息進(jìn)行處理。
  • ConcreteSubject具體的被觀察者,定義被觀察者自己的業(yè)務(wù)邏輯,同時(shí)定義對(duì)哪些事件進(jìn)行通知。
  • ConcreteObserver具體的觀察者,每個(gè)觀察者接收到消息后的處理反應(yīng)是不同的,每個(gè)觀察者都有自己的處理邏輯。

觀察者模式的優(yōu)點(diǎn)

  • 觀察者和被觀察者之間是抽象耦合,不管是增加觀察者還是被觀察者都非常容易擴(kuò)展。
  • 建立一套觸發(fā)機(jī)制。

觀察者模式的缺點(diǎn)

觀察者模式需要考慮開發(fā)效率和運(yùn)行效率問題,一個(gè)被觀察者,多個(gè)觀察者,開發(fā)和調(diào)試比較復(fù)雜,Java消息的通知默認(rèn)是順序執(zhí)行的,一個(gè)觀察者卡殼,會(huì)影響整體的執(zhí)行效率。這種情況一般考慮異步的方式。

使用場(chǎng)景

  • 關(guān)聯(lián)行為場(chǎng)景,關(guān)聯(lián)是可拆分的。
  • 事件多級(jí)觸發(fā)場(chǎng)景。
  • 跨系統(tǒng)的消息交換場(chǎng)景,如消息隊(duì)列的處理機(jī)制。

Java中的觀察者模式

java.util.Observable類和java.util.Observer接口。

訂閱發(fā)布模型

觀察者模式也叫作發(fā)布/訂閱模式。

Spring中的觀察者模式

Spring在事件處理機(jī)制中使用了觀察者模式:

  • 事件,ApplicationEvent,該抽象類繼承了EventObject,EventObject是JDK中的類,并建議所有的事件都應(yīng)該繼承自EventObject。
  • 事件監(jiān)聽器,ApplicationListener,是一個(gè)接口,該接口繼承了EventListener接口。EventListener接口是JDK中的,建議所有的事件監(jiān)聽器都應(yīng)該繼承EventListener。
  • 事件發(fā)布,ApplicationEventPublisher,ApplicationContext繼承了該接口,在ApplicationContext的抽象實(shí)現(xiàn)類AbstractApplicationContext中做了實(shí)現(xiàn)

AbstractApplicationContext類中publishEvent方法實(shí)現(xiàn):

public void publishEvent(ApplicationEvent event) {
    Assert.notNull(event, "Event must not be null");
    if (logger.isTraceEnabled()) {
        logger.trace("Publishing event in " + getDisplayName() + ": " + event);
    }
    //事件發(fā)布委托給ApplicationEventMulticaster來執(zhí)行
    getApplicationEventMulticaster().multicastEvent(event);
    if (this.parent != null) {
        this.parent.publishEvent(event);
    }
}

ApplicationEventMulticaster的multicastEvent方法的實(shí)現(xiàn)在SimpleApplicationEventMulticaster類中:

public void multicastEvent(final ApplicationEvent event) {
    //獲得監(jiān)聽器集合,遍歷監(jiān)聽器,可支持同步和異步的廣播事件
    for (final ApplicationListener listener : getApplicationListeners(event)) {
        Executor executor = getTaskExecutor();
        if (executor != null) {
            executor.execute(new Runnable() {
                public void run() {
                    listener.onApplicationEvent(event);
                }
            });
        }
        else {
            listener.onApplicationEvent(event);
        }
    }
}

這就執(zhí)行了了onApplicationEvent方法,這里是事件發(fā)生的地方。

Spring如何根據(jù)事件找到事件對(duì)應(yīng)的監(jiān)聽器

在Spring容器初始化的時(shí)候,也就是在refresh方法中:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        ......
        try {
            ......
            // Initialize event multicaster for this context.
            //初始化一個(gè)事件注冊(cè)表
            initApplicationEventMulticaster();
            ......
            // Check for listener beans and register them.
            //注冊(cè)事件監(jiān)聽器
            registerListeners();

            ......
        }
    }
}

initApplicationEventMulticaster方法初始化事件注冊(cè)表:

protected void initApplicationEventMulticaster() {
    //獲得beanFactory
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    //先查找BeanFactory中是否有ApplicationEventMulticaster
    if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
        this.applicationEventMulticaster =
                beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    }
    else {//如果BeanFactory中不存在,就創(chuàng)建一個(gè)SimpleApplicationEventMulticaster
        this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
        beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    }
}

在AbstractApplicationEventMulticaster類中有如下屬性:

//注冊(cè)表
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
//注冊(cè)表的緩存
private final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<ListenerCacheKey, ListenerRetriever>(64);

private BeanFactory beanFactory;

ListenerRetriever的結(jié)構(gòu)如下:

//用來存放監(jiān)聽事件
public final Set<ApplicationListener> applicationListeners;
//存放監(jiān)聽事件的類名稱
public final Set<String> applicationListenerBeans;

private final boolean preFiltered;

初始化注冊(cè)表之后,就會(huì)把事件注冊(cè)到注冊(cè)表中,registerListeners():

protected void registerListeners() {
    //獲取所有的Listener,把事件的bean放到ApplicationEventMulticaster中
    for (ApplicationListener<?> listener : getApplicationListeners()) {
        getApplicationEventMulticaster().addApplicationListener(listener);
    }
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let post-processors apply to them!
    String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
    //把事件的名稱放到ApplicationListenerBean里去。
    for (String lisName : listenerBeanNames) {
        getApplicationEventMulticaster().addApplicationListenerBean(lisName);
    }
}

Spring使用反射機(jī)制,通過方法getBeansOfType獲取所有繼承了ApplicationListener接口的監(jiān)聽器,然后把監(jiān)聽器放到注冊(cè)表中,所以我們可以在Spring配置文件中配置自定義監(jiān)聽器,在Spring初始化的時(shí)候,會(huì)把監(jiān)聽器自動(dòng)注冊(cè)到注冊(cè)表中去。

ApplicationContext發(fā)布事件可以參考上面的內(nèi)容。發(fā)布事件的時(shí)候的一個(gè)方法,getApplicationListeners:

protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
    //獲取事件類型
    Class<? extends ApplicationEvent> eventType = event.getClass();
    //或去事件源類型
    Class sourceType = event.getSource().getClass();
    ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    //從緩存中查找ListenerRetriever
    ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
    //緩存中存在,直接返回對(duì)應(yīng)的Listener
    if (retriever != null) {
        return retriever.getApplicationListeners();
    }
    else {//緩存中不存在,就獲取相應(yīng)的Listener
        retriever = new ListenerRetriever(true);
        LinkedList<ApplicationListener> allListeners = new LinkedList<ApplicationListener>();
        Set<ApplicationListener> listeners;
        Set<String> listenerBeans;
        synchronized (this.defaultRetriever) {
            listeners = new LinkedHashSet<ApplicationListener>(this.defaultRetriever.applicationListeners);
            listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
        }
        //根據(jù)事件類型,事件源類型,獲取所需要的監(jiān)聽事件
        for (ApplicationListener listener : listeners) {
            if (supportsEvent(listener, eventType, sourceType)) {
                retriever.applicationListeners.add(listener);
                allListeners.add(listener);
            }
        }
        if (!listenerBeans.isEmpty()) {
            BeanFactory beanFactory = getBeanFactory();
            for (String listenerBeanName : listenerBeans) {
                ApplicationListener listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
                if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
                    retriever.applicationListenerBeans.add(listenerBeanName);
                    allListeners.add(listener);
                }
            }
        }
        OrderComparator.sort(allListeners);
        this.retrieverCache.put(cacheKey, retriever);
        return allListeners;
    }
}

根據(jù)事件類型,事件源類型獲取所需要的監(jiān)聽器supportsEvent(listener, eventType, sourceType):

protected boolean supportsEvent(
        ApplicationListener listener, Class<? extends ApplicationEvent> eventType, Class sourceType) {

    SmartApplicationListener smartListener = (listener instanceof SmartApplicationListener ?
            (SmartApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

這里沒有進(jìn)行實(shí)際的處理,實(shí)際處理在smartListener.supportsEventType(eventType)和smartListener.supportsSourceType(sourceType)方法中。

smartListener.supportsEventType(eventType):

public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
    if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
        Class targetClass = AopUtils.getTargetClass(this.delegate);
        if (targetClass != this.delegate.getClass()) {
            typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
        }
    }
    return (typeArg == null || typeArg.isAssignableFrom(eventType));
}

該方法主要的邏輯就是根據(jù)事件類型判斷是否和監(jiān)聽器參數(shù)泛型的類型是否一致。

smartListener.supportsSourceType(sourceType)方法的實(shí)現(xiàn)為:

public boolean supportsSourceType(Class<?> sourceType) {
    return true;
}

定義自己的監(jiān)聽器要明確指定參數(shù)泛型,表明該監(jiān)聽器支持的事件,如果不指明具體的泛型,則沒有監(jiān)聽器監(jiān)聽事件。

還可以定義自己的事件

暫先不做解析。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,680評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,283評(píng)論 6 342
  • Spring容器高層視圖 Spring 啟動(dòng)時(shí)讀取應(yīng)用程序提供的Bean配置信息,并在Spring容器中生成一份相...
    Theriseof閱讀 2,920評(píng)論 1 24
  • 突然相信冥冥之中有雙眼睛在盯著你,你的一切舉動(dòng)它都能看見,你的努力它會(huì)記下,你的放縱他也看在眼里,適時(shí)它會(huì)把你做的...
    冷兔仙子閱讀 280評(píng)論 0 0
  • 動(dòng)作一 ▼ 杠鈴深蹲 下蹲時(shí)要盡量保持上身直立,不要向前彎腰,否則杠鈴重量都在脖子上,要蹲深一些蹲到大腿與小腿呈9...
    暈暈乎乎er閱讀 387評(píng)論 0 1

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