前言
上一篇 Spring 事件機(jī)制概述 的文章中枷莉,從觀察者模式熬词、Java 事件機(jī)制轮听、Spring 事件機(jī)制的具體代碼實現(xiàn)進(jìn)行了簡要的分析卷谈。本篇文章將在其基礎(chǔ)上對 Spring 事件機(jī)制的源碼進(jìn)行分析杯拐。
- Spring 事件機(jī)制流程回顧
- 創(chuàng)建一個具體的事件類,該類需繼承 ApplicationEvent雏搂;
- 創(chuàng)建一個針對某個特定時間的監(jiān)聽器實現(xiàn) ApplicationListener藕施,并配置 @Component 注解,確保 Ioc 容器啟動時凸郑,監(jiān)聽器會注入至 Ioc 容器裳食;
- 初始化 Ioc 容器;
- 由于 ApplicationContext 實現(xiàn)了 ApplicationEventPublisher芙沥,因此直接使用 ApplicationContext 作為事件發(fā)布器發(fā)布某個事件诲祸,此時該事件的監(jiān)聽器便會接收到事件并做出相應(yīng)的處理。此處也可以通過實現(xiàn) ApplicationEventPublisherAware 接口而昨,來獲得事件發(fā)布器救氯。
上述的流程中,可能會有這樣一些疑問:
- 事件監(jiān)聽器是何時被注入的歌憨?
- 事件發(fā)布器是怎么樣對具體的事件進(jìn)行發(fā)布着憨?
帶著這兩個疑問,開始源碼的分析务嫡。
Spring 事件機(jī)制源碼分析
在實際應(yīng)用的代碼中甲抖,Ioc 容器 ApplicationContext 創(chuàng)建完成后,監(jiān)聽器 ApplicationListener 及發(fā)布器 ApplicationEventPublisher 均已就緒心铃,可直接使用進(jìn)行事件發(fā)布准谚,故從 ApplicationContext 初始化著手來分析。 通過對 Spring Ioc 的源碼分析去扣,我們知道了容器初始化的核心方法為 AbstractApplicationContext::refresh柱衔,查看 refresh 方法,我們發(fā)現(xiàn)有兩個方法與 Spring 的事件相關(guān)愉棱。
-
initApplicationEventMulticaster 方法
-
ApplicationEventMulticaster(事件多播器)
ApplicationEventMulticaster 接口的方法主要是操作 ApplicationListener, 廣播 ApplicationEventpublic interface ApplicationEventMulticaster { void addApplicationListener(ApplicationListener<?> listener); void addApplicationListenerBean(String listenerBeanName); void removeApplicationListener(ApplicationListener<?> listener); void removeApplicationListenerBean(String listenerBeanName); void removeAllListeners(); void multicastEvent(ApplicationEvent event); void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType); }
分析其繼承關(guān)系唆铐,在抽象類 AbstractApplicationEventMulticaster 中實現(xiàn)了接口的方法,SimpleApplicationEventMulticaster 中引入異步操作的支持奔滑。相關(guān)源碼會在后面串聯(lián)分析或链。
ApplicationEventMulticaster -
源碼
源碼的核心流程是,先判斷 BeanFactory 中有沒有 ApplicationEventMulticaster 類档押,若有則賦值給本地變量,若無則創(chuàng)建 SimpleApplicationEventMulticaster 并賦值給本地變量。protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 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 { 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 + "]"); } } }
-
-
registerListeners
- 源碼分析
從 registerListeners 源碼中可以看到令宿,該方法中只是將 ApplicationListener 對應(yīng)的 BeanName 保存起來了叼耙,因此這個時候 Bean 都還沒有完成初始化,只有 beanDefinition 的信息粒没,后續(xù)在完成 Bean 初始化后筛婉,會調(diào)用一個后置處理器 ApplicationListenerDetector 的 postProcessAfterInitialization 方法,將 ApplicationListener 對應(yīng)的 Bean 實例綁定到 ApplicationEventMulticaster 中癞松。
protected void registerListeners() { // Register statically specified listeners first. // getApplicationListeners 方法中返回本地的 applicationListeners 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! // 從 BeanFactory 中找到 ApplicationListener 類所對應(yīng)的所有 BeanName 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... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
- 源碼分析
在完成 ApplicationEventMulticaster 初始化爽撒,監(jiān)聽器注入后,后續(xù)就是如何發(fā)布事件响蓉,從 ApplicationContext 的類繼承關(guān)系中知道硕勿,該類繼承了 ApplicationEventPublisher,在 AbstractApplicationContext 類中實現(xiàn)了方法 publishEvent枫甲,具體源碼為:
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
// Decorate event as an ApplicationEvent if necessary
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 {
// 使用事件廣播器廣播該事件
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// getApplicationListeners 根據(jù) event 的類型找到相應(yīng)的 listener
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 增加了對異步事件的支持源武,如果 executor 不為空則異步通知該事件
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
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);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
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.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
總結(jié)
從上述的分析中可知,Spring 事件發(fā)布的主要流程為:
- 初始化 事件多播器(ApplicationEventMulticaster)
- 注冊 ApplicationListener
- 調(diào)用后置處理器 ApplicationListenerDetector 完成 ApplicationEventMulticaster 中 listener 實例的賦值想幻;
- 發(fā)布事件時粱栖,調(diào)用 ApplicationEventMulticaster 的廣播方法,將 Event 廣播至對應(yīng)的 Listener脏毯。
Spring 提供了以下 5 中標(biāo)準(zhǔn)的事件闹究,我們可以注冊響應(yīng)的監(jiān)聽器進(jìn)行處理該事件。
- 上下文更新事件(ContextRefreshedEvent):在調(diào)用ConfigurableApplicationContext 接口中的refresh()方法時被觸發(fā)食店。
- 上下文開始事件(ContextStartedEvent):當(dāng)容器調(diào)用ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發(fā)該事件渣淤。
- 上下文停止事件(ContextStoppedEvent):當(dāng)容器調(diào)用ConfigurableApplicationContext的Stop()方法停止容器時觸發(fā)該事件。
- 上下文關(guān)閉事件(ContextClosedEvent):當(dāng)ApplicationContext被關(guān)閉時觸發(fā)該事件叛买。容器被關(guān)閉時砂代,其管理的所有單例Bean都被銷毀。
- 請求處理事件(RequestHandledEvent):在Web應(yīng)用中率挣,當(dāng)一個http請求(request)結(jié)束觸發(fā)該事件刻伊。