Spring源碼閱讀----Spring事件監(jiān)聽機(jī)制

概述

經(jīng)過(guò)IoC的解析,我們需要將注意力再拉回到refresh方法中。我們還有這幾個(gè)方法還沒解析完:

image.png

這里繼續(xù),先來(lái)講Spring事件監(jiān)聽機(jī)制。

Spring事件監(jiān)聽

在業(yè)務(wù)開發(fā)過(guò)程中為了解耦,我們可能或多或少接觸過(guò)MQ消息隊(duì)列這東西或者對(duì)設(shè)計(jì)模式中的觀察者模式了解的話,實(shí)現(xiàn)事件監(jiān)聽需要的組成部分有這幾個(gè):

  • 事件(Event)
  • 事件生產(chǎn)者(Publisher)
  • 事件消費(fèi)者(Consumer)
  • 管理中介(Broker)

是不是很熟悉?Spring中是用事件、事件監(jiān)聽器、事件發(fā)布者和事件廣播器來(lái)實(shí)現(xiàn)

  • 事件(ApplicationEvent)
  • 事件監(jiān)聽器(ApplicationListener)
  • 事件發(fā)布者(ApplicationEventPublisher)
  • 事件廣播器(ApplicationEventMulticaster)

它們的關(guān)系如下圖:

Spring事件

那這里解析一下refresh中的這幾個(gè)方法:
initApplicationEventMulticaster():初始化應(yīng)用的事件廣播器(見源碼解析1)
registerListeners():注冊(cè)監(jiān)聽器(見源碼解析2)
finishRefresh():完成上下文的刷新工作(見源碼解析3)

【源碼解析1】 初始化應(yīng)用的事件廣播器:initApplicationEventMulticaster方法

    protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 如有有自己注冊(cè)class Name 是 applicationEventMulticaster,使用自定義廣播器
        //APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster"
        if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
            this.applicationEventMulticaster =
                    beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
            if (logger.isTraceEnabled()) {
                logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        }
        else {
            // 沒有自定義,使用默認(rèn)的事件廣播器
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
            if (logger.isTraceEnabled()) {
                logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
                        "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }
    }

事件廣播器beanName :applicationEventMulticaster。
如果有自定義的廣播器已經(jīng)在beanFactory中注冊(cè),則使用該廣播器;
若沒有自定義的廣播器的情況下,創(chuàng)建一個(gè)默認(rèn)的事件廣播器SimpleApplicationEventMulticaster,查看一下其類圖:

SimpleApplicationEventMulticaster

【源碼解析2】 注冊(cè)監(jiān)聽器 : registerListeners方法

    protected void registerListeners() {
        // Register statically specified listeners first.
        // 這里是硬編碼注冊(cè)的監(jiān)聽器((可以通過(guò)自定義ApplicationContextInitializer添加))
        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!
        // 不要在這里初始化 factoryBean : 我們需要保留所有常規(guī) bean 未初始化,以便讓后處理程序應(yīng)用于它們!
        // 通過(guò)配置文件或注解注入BeanFactory的監(jiān)聽器處理
        String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
        for (String listenerBeanName : listenerBeanNames) {
            getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
        }

        // Publish early application events now that we finally have a multicaster...
        // 使用事件廣播器,發(fā)布早期應(yīng)用程序事件到相應(yīng)的監(jiān)聽器
        Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
        this.earlyApplicationEvents = null;
        if (earlyEventsToProcess != null) {
            for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
                getApplicationEventMulticaster().multicastEvent(earlyEvent);
            }
        }
    }

到這個(gè)階段,事件廣播器和監(jiān)聽器都在Spring容器里初始化和注冊(cè)了,之后就可以實(shí)現(xiàn)監(jiān)聽者模式了,對(duì)事件的發(fā)布進(jìn)行監(jiān)聽然后處理。繼續(xù)看finishRefresh里的內(nèi)容。

finishRefresh

finishRefresh方法源碼如下:

    protected void finishRefresh() {
        // Clear context-level resource caches (such as ASM metadata from scanning).
        //清除resourceCaches資源緩存中的數(shù)據(jù)
        clearResourceCaches();

        // Initialize lifecycle processor for this context.
        //注釋1. 為此上下文初始化生命周期處理器
        initLifecycleProcessor();

        // Propagate refresh to lifecycle processor first.
        //注釋2. 首先將刷新完畢事件傳播到生命周期處理器(觸發(fā)isAutoStartup方法返回true的SmartLifecycle的start方法)
        getLifecycleProcessor().onRefresh();

        // Publish the final event.
        //注釋3. 推送上下文刷新完畢事件到相應(yīng)的監(jiān)聽器
        publishEvent(new ContextRefreshedEvent(this));

        // Participate in LiveBeansView MBean, if active.
        LiveBeansView.registerApplicationContext(this);
    }

這里主要講注釋3,另外的解析放到后文里詳解。
注釋3.推送上下文刷新完畢事件到相應(yīng)的監(jiān)聽器 publishEvent(見源碼解析4)

【源碼解析4】 推送上下文刷新完畢事件到相應(yīng)的監(jiān)聽器:publishEvent方法

    @Override
    public void publishEvent(Object event) {
        publishEvent(event, null);
    }

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
        Assert.notNull(event, "Event must not be null");

        // Decorate event as an ApplicationEvent if necessary
        //如果必需的話把event裝飾成ApplicationEvent 
        ApplicationEvent applicationEvent;
        if (event instanceof ApplicationEvent) {
            applicationEvent = (ApplicationEvent) event;
        }
        else {
            applicationEvent = new PayloadApplicationEvent<>(this, event);
            if (eventType == null) {
                eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
            }
        }

        // Multicast right now if possible - or lazily once the multicaster is initialized
        if (this.earlyApplicationEvents != null) {
            this.earlyApplicationEvents.add(applicationEvent);
        }
        else {
            //注釋1. 使用事件廣播器廣播事件到相應(yīng)的監(jiān)聽器
            getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
        }

        // Publish event via parent context as well...
        // 通過(guò)parent發(fā)布事件
        if (this.parent != null) {
            if (this.parent instanceof AbstractApplicationContext) {
                ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
            }
            else {
                this.parent.publishEvent(event);
            }
        }
    }

注釋1. 使用事件廣播器廣播事件到相應(yīng)的監(jiān)聽器
getApplicationEventMulticaster()獲取事件廣播器
multicastEvent()廣播事件到相應(yīng)的監(jiān)聽器(見源碼解析5)

【源碼解析5】 SimpleApplicationEventMulticaster類的multicastEvent方法

    @Override
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));

        //獲取任務(wù)執(zhí)行器executor 
        Executor executor = getTaskExecutor();

        // 遍歷注冊(cè)的消息監(jiān)聽器(getApplicationListeners)
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                //executor不為null,則使用executor調(diào)用監(jiān)聽器
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                // 直接調(diào)用監(jiān)聽器
                invokeListener(listener, event);
            }
        }
    }

在前面我們已經(jīng)提到過(guò)SimpleApplicationEventMulticaster,是Spring默認(rèn)的事件廣播器。
調(diào)用監(jiān)聽器invokeListener方法(見源碼解析6)

【源碼解析6】 調(diào)用監(jiān)聽器:invokeListener方法,真正做事的為doInvokeListener方法

    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                doInvokeListener(listener, event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            doInvokeListener(listener, event);
        }
    }

    //執(zhí)行調(diào)用監(jiān)聽器
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {

            //觸發(fā)監(jiān)聽器的onApplicationEvent方法,參數(shù)為給定的事件
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }

好了,在這里我們可以發(fā)現(xiàn),監(jiān)聽器里邊的onApplicationEvent方法被觸發(fā)了,所以,從這一個(gè)流程下來(lái),我們可以看到一個(gè)事件的發(fā)布,可以篩選出對(duì)應(yīng)的監(jiān)聽器并觸發(fā)其onApplicationEvent,執(zhí)行相應(yīng)的操作。

自定義一個(gè)事件和監(jiān)聽器
1.創(chuàng)建一個(gè)下單事件OrderEvent

public class OrderEvent extends ApplicationEvent{
                
         public OrderEvent(ApplicationContext source) {
             super(source);
             System.out.println("構(gòu)建下單事件");
         }
}
  1. 創(chuàng)建一個(gè)監(jiān)聽器監(jiān)聽下單事件
@Component
public class OrderListener implements ApplicationListener<OrderEvent>  {

    @Override
    public void onApplicationEvent(OrderEvent orderEvent) {
        System.out.println("訂單監(jiān)聽器監(jiān)聽到下單事件,訂單號(hào)為:20210201100001");
        //后續(xù)業(yè)務(wù)邏輯....
    }
}
  1. 在前文的demo基礎(chǔ)上,修改main函數(shù)
public  class App {

    public static void main(String[] args) throws ClassNotFoundException {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderEvent orderEvent = new OrderEvent(context);
        context.publishEvent(orderEvent);
    }
}

這樣容器初始化后,會(huì)執(zhí)行發(fā)布下單事件,并將事件推送到OrderListener 監(jiān)聽器中,并觸發(fā)onApplicationEvent,執(zhí)行效果如下:

OrderEvent

※Spring的事件監(jiān)聽機(jī)制是同步處理的,具體留給大家自己探索一下,可以打印每個(gè)事件監(jiān)聽器處理時(shí)的線程名,是否跟主線程是同一個(gè)。是否可以進(jìn)行異步改造?

如果一個(gè)事件有多個(gè)監(jiān)聽器,如何給這些監(jiān)聽器排序呢?
用前文解析代碼的時(shí)候提到的 ,bean實(shí)現(xiàn)Ordered接口和PriorityOrdered接口
這樣重寫其getOrder方法,設(shè)置這些監(jiān)聽器的觸發(fā)順序。

總結(jié)

好了,事件監(jiān)聽機(jī)制就介紹到這里,掌握觀察者模式以及ApplicationEventMulticaster、ApplicationListener、ApplicationEvent、ApplicationEventPublisher這幾個(gè)組件的關(guān)系,以及事件觸發(fā)執(zhí)行流程。下一節(jié)介紹finishRefresh中剩下的幾個(gè)方法。

最后編輯于
?著作權(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ù)。

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