Spring事件監(jiān)聽源碼解析流程分析
spring事件監(jiān)聽機制離不開容器IOC特性提供的支持,比如容器會自動創(chuàng)建事件發(fā)布器,自動識別用戶注冊的監(jiān)聽器并進行管理,在特定的事件發(fā)布后會找到對應的事件監(jiān)聽器并對其監(jiān)聽方法進行回調。Spring幫助用戶屏蔽了關于事件監(jiān)聽機制背后的很多細節(jié),使用戶可以專注于業(yè)務層面進行自定義事件開發(fā)。然而我們對內部的實現(xiàn)還是有一些疑問,比如:
• 事件發(fā)布器ApplicationEventMulticaster是何時被初始化的,初始化過程中都做了什么?
• 注冊事件監(jiān)聽器的過程是怎樣的,容器怎么識別出它們并進行管理?
• 容器發(fā)布事件的流程是怎樣的?它如何根據(jù)發(fā)布的事件找到對應的事件監(jiān)聽器,事件和由該事件觸發(fā)的監(jiān)聽器之間的匹配規(guī)則是怎樣的?
初始化事件發(fā)布器流程
真正的事件發(fā)布器是ApplicationEventMulticaster,它定義在AbstractApplicationContext中,并在ApplicationContext容器啟動的時候進行初始化。在容器啟動的refrsh()方法中可以找到初始化事件發(fā)布器的入口方法,如下圖所示:

/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
* @see org.springframework.context.event.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.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
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() + "]");
}
}
}這里會根據(jù)核心容器beanFactory中是否有id為applicationEventMulticaster的bean分兩種情況:
(1)容器中已有id為applicationEventMulticaster的bean:直接從容器緩存獲取或是創(chuàng)建該bean實例,并交由成員變量applicationEventMulticaster保存。當用戶自定義了事件發(fā)布器并向容器注冊時會執(zhí)行該流程。
(2)容器中不存在applicationEventMulticaster的bean:這是容器默認的執(zhí)行流程,會創(chuàng)建一個SimpleApplicationEventMulticaster,其僅在實現(xiàn)事件發(fā)布器基本功能(管理事件監(jiān)聽器以及發(fā)布容器事件)的前提下,增加了可以設置任務執(zhí)行器Executor和錯誤處理器ErrorHandler的功能,當設置Executor為線程池時,則會以異步的方式對事件監(jiān)聽器進行回調,而ErrorHandler允許我們在回調方法執(zhí)行錯誤時進行自定義處理。默認情況下,這兩個變量都為null。

之后會調用beanFactory.registerSingleton方法將創(chuàng)建的SimpleApplicationEventMulticaster實例注冊為容器的單實例bean。
初始化事件發(fā)布器總結一句話:由容器實例化用戶自定義的事件發(fā)布器或者由容器幫我們創(chuàng)建一個簡單的事件發(fā)布器并交由容器管理。
注冊事件監(jiān)聽器流程
注冊事件監(jiān)聽器的流程在初始化事件發(fā)布器之后,如下圖所示:

/**
* Add beans that implement ApplicationListener as listeners.
* Doesn't affect other listeners, which can be added without being beans.
*/
protected void registerListeners() {
// 首先注冊靜態(tài)指定的監(jiān)聽器。
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 不要在這里初始化FactoryBeans:我們需要保留所有常規(guī)Bean
// 未初始化以允許后處理器應用于它們!
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 發(fā)布早期應用程序事件
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}容器事件發(fā)布流程
org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, ResolvableType)
將給定事件發(fā)布給所有偵聽器

前面說,在啟動的時候如果沒有一個beanName叫做applicationEventMulticaster的ApplicationEventMulticaster,那使用的就是SimpleApplicationEventMulticaster,該組件會在容器啟動時被自動創(chuàng)建,并以單例的形式存在,管理了所有的事件監(jiān)聽器,并提供針對所有容器內事件的發(fā)布功能。
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//獲取事件類型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//獲取事件發(fā)布器內的任務執(zhí)行器,默認該方法返回null
Executor executor = getTaskExecutor();
//遍歷所有和事件匹配的事件監(jiān)聽器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
//異步回調監(jiān)聽方法
executor.execute(() -> invokeListener(listener, event));
} else {
//同步回調監(jiān)聽方法
invokeListener(listener, event);
}
}
}如何根據(jù)事件類型找到匹配的所有事件監(jiān)聽器?
org.springframework.context.event.AbstractApplicationEventMulticaster#getApplicationListeners(ApplicationEvent, ResolvableType)
/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @param eventType the event type
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// 獲取事件中的事件源對象
Object source = event.getSource();
// 獲取事件源類型
Class<?> sourceType = (source != null ? source.getClass() : null);
// 以事件類型和事件源類型為參數(shù)構建一個cacheKey ,用于從緩存map中獲取與之匹配的監(jiān)聽器列表
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 根據(jù)cacheKey從緩存中獲取CachedListenerRetriever
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 不存在就檢索給定事件和源類型的應用程序偵聽器,并放到緩存
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}如果事件時第一次發(fā)布,會遍歷所有的事件監(jiān)聽器,并根據(jù)事件類型和事件源類型進行匹配:
org.springframework.context.event.AbstractApplicationEventMulticaster#retrieveApplicationListeners
/**
* Actually retrieve the application listeners for the given event and source type.
* @param eventType the event type
* @param sourceType the event source type
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
* @return the pre-filtered list of application listeners for the given event and source type
*/
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
// 存放監(jiān)聽器的列表
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// 添加以編程方式注冊的偵聽器,
// 包括來自ApplicationListenerDetector的偵聽器(單例bean和內部bean)。
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
// 按bean名稱添加偵聽器,這可能與上面通過編程注冊的偵聽器重疊,
// 但這里可能有額外的元數(shù)據(jù)。
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
// 刪除最初來自ApplicationListenerDetector的不匹配偵聽器,
// 可能會被上面額外的BeanDefinition元數(shù)據(jù)(例如工廠方法泛型)排除。
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// 單一偵聽器實例(沒有支持bean定義)消失-可能在銷毀階段中期}
}
}
//對匹配的監(jiān)聽器列表進行排序
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}容器事件發(fā)布的整個流程,可以總結如下:

到此這篇關于Spring事件監(jiān)聽源碼解析的文章就介紹到這了,更多相關Spring事件監(jiān)聽內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
在java8中使用流區(qū)分質數(shù)與非質數(shù)詳解
這篇文章主要介紹了在java8中使用流區(qū)分質數(shù)與非質數(shù)詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Jackson庫進行JSON?序列化時遇到了無限遞歸(Infinite?Recursion)的問題及解決方案
使用Jackson庫進行JSON序列化時遇到了無限遞歸(Infinite?Recursion)問題,這是因為兩個實體類ComPointQuotaEntity和?ComPointEntity之間存在雙向關聯(lián)point和pointQuota相互引用,本文給大家介紹解決方案,感興趣的朋友一起看看吧2025-03-03
Java之maven打完jar包之后將jar包放到指定位置匯總
這篇文章主要介紹了Java之maven打完jar包之后將jar包放到指定位置匯總,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04
spring boot實戰(zhàn)之內嵌容器tomcat配置
本篇文章主要介紹了Spring Boot 使用內嵌的tomcat容器配置,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01

