注意:該源碼分析對應版本爲spring5.1.x
1,概述
本篇開始分析Spring的事件機制源碼,因爲Spring的事件機制實質是觀察者(發佈訂閱)模式的實現,因此要想搞清楚Spring的事件機制,因此得知道觀察者模式是什麼。同時推薦閱讀下這篇文章的前奏文章,對於理解spring的事件機制非常有幫助,推薦我都另一篇翻譯的博文:
模仿Spring事件機制實現自定義事件驅動編程--Spring的事件機制源碼分析(一)
在開始正題前,先聊聊研究源碼的感受:研究源碼前那麼必須先搞清楚類與類之間的關係,比如某個接口有哪些實現類,某個父類有哪些子類,子類與子類之間的關係,這些類之間的關係捋清楚了,那麼再下手研究源碼就容易很多。總之不能一下子就進入源碼的某個細節,這樣子就會造成只見冰山一角而看不到全貌的感覺。
好了,下面開始進入正題,開始學習Spring的事件機制。因爲編碼一般都是面向接口編程,那麼我們先從事件機制的相關接口或抽象類開始分析。
Spring事件機制涉及的重要的類主要有以下四個:
- ApplicationEvent:事件,該抽象類是所有Spring事件的父類,可攜帶數據比如事件發生時間timestamp。
- ApplicationListener:事件監聽器,該接口被所有的事件監聽器實現,基於標準的java的EventListener接口實現觀察者模式。
- ApplicationEventMulticaster:事件管理者,管理監聽器和發佈事件,ApplicationContext通過委託ApplicationEventMulticaster來 發佈事件
- ApplicationEventPublisher:事件發佈者,該接口封裝了事件有關的公共方法,作爲ApplicationContext的超級街廓,也是委託 ApplicationEventMulticaster完成事件發佈。
2,Spring事件涉及類源碼分析
事件相關的主要接口類上面已經介紹完畢,下面來看下每個接口及其子類之間的關係。
2.1 ApplicationEvent
首先看下類圖如下:
圖1
其接口代碼如下:
// 事件抽象類,這個是所有Spring事件的父類
public abstract class ApplicationEvent extends EventObject {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 7099057708183571937L;
/** System time when the event happened. */
private final long timestamp;
/**
* Create a new ApplicationEvent.
* @param source the object on which the event initially occurred (never {@code null})
*/
public ApplicationEvent(Object source) {
super(source);
this.timestamp = System.currentTimeMillis();
}
/**
* Return the system time in milliseconds when the event happened.
*/
public final long getTimestamp() {
return this.timestamp;
}
}
ApplicationEvent類定義了一些屬性比如timestamp,這個表示事件的發生時間,因此可以通過事件來傳遞一些參數。
圖1是ApplicationEvent部分重要的子類關係圖,其中ApplicationEvent最重要的子類是ApplicationContextEvent抽象類,ApplicationContextEvent是spring容器Context生命週期事件的基類,ApplicationContextEvent的有四個子類,如下:
- ContextRefreshedEvent:當spring容器context刷新時觸發
- ContextStartedEvent:當spring容器context啓動後觸發
- ContextStoppedEvent:當spring容器context停止時觸發
- ContextClosedEvent:當spring容器context關閉時觸發,容器被關閉時,其管理的所有單例Bean都被銷燬。
以上四個事件就是spring容器生命週期的四個事件,當每個事件觸發時,相關的監聽器就會監聽到相應事件,然後觸發onApplicationEvent方法,此時就可以做一些容器,同時這些容器事件跟spring的後置處理器一樣,留給用戶擴展自定義邏輯,作爲暴露的擴展點。
以ContextRefreshedEvent事件爲例講解下相關監聽類,通過idea全局搜索"(ContextRefreshedEvent"關鍵字,得到以下截圖:
從上圖可以看到spring-webmvc模塊的FrameworkServlet,spring-context模塊的ScheduledAnnotationBeanPostProcessor,和spring-jms模塊的JmsListenerEndpointRegistry等類訂閱了ContextRefreshedEvent事件,那麼在容器刷新的時候這幾個類將會監聽到ContextRefreshedEvent事件,執行一些初始化邏輯。這一塊後面有時間再研究,TODO。
下面粘貼下ApplicationContextEvent的四個子類的實現代碼,基本都是繼承ApplicationContextEvent父類,沒有什麼邏輯,更多是一個生命週期事件的標誌類。
public class ContextRefreshedEvent extends ApplicationContextEvent {
// 當springcontext已經被初始化或者刷新的時候,創建該事件
public ContextRefreshedEvent(ApplicationContext source) {
super(source);
}
}
public class ContextStartedEvent extends ApplicationContextEvent {
// 當springContext已經啓動的時候,創建該事件
public ContextStartedEvent(ApplicationContext source) {
super(source);
}
}
public class ContextStoppedEvent extends ApplicationContextEvent {
// 當springContext已經停止時創建該事件
public ContextStoppedEvent(ApplicationContext source) {
super(source);
}
}
public class ContextClosedEvent extends ApplicationContextEvent {
// 當springContext關閉時創建該事件
public ContextClosedEvent(ApplicationContext source) {
super(source);
}
}
2.2 ApplicationListener
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
void onApplicationEvent(E event);
}
ApplicationListener是所有事件監聽器的父接口,事件監聽器監聽某個事件必須要實現該接口。這裏值得注意的是ApplicationListener<E extends ApplicationEvent>接口的參數化類型<E extends ApplicationEvent>,這樣的話具體的監聽器實現該接口時可以指定特定的事件類,當傳入的事件向下轉型時不是該特定的事件時,此時會拋出類轉換異常。不過一般使用的時候會先判斷下該事件類型是否屬於某種事件,然後再執行相關邏輯,如下代碼:
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
由於ApplicationListener接口的具體實現類太多,因此就不貼類關係圖了。
2.2 ApplicationEventMulticaster
首先看下類圖,
ApplicationEventMulticaster接口功能主要用來廣播事件給所有listener,主要定義了增刪改監聽器和廣播事件的接口方法,代碼如下:
public interface ApplicationEventMulticaster {
void addApplicationListener(ApplicationListener<?> var1);
void addApplicationListenerBean(String var1);
void removeApplicationListener(ApplicationListener<?> var1);
void removeApplicationListenerBean(String var1);
void removeAllListeners();
void multicastEvent(ApplicationEvent var1);
void multicastEvent(ApplicationEvent var1, @Nullable ResolvableType var2);
}
AbstractApplicationEventMulticaster是ApplicationEventMulticaster接口的抽象實現,提供最基本的監聽器註冊的方法。註冊監聽器時一般不允許相同監聽器註冊多個實例,因此使用Set集合,用於去重。然後實現廣播事件的具體實現沒有在這裏實現,而是交給子類SimpleApplicationEventMulticaster去實現。
AbstractApplicationEventMulticaster抽象類的關鍵代碼如下:
// AbstractApplicationEventMulticaster.java
/**
* 獲取事件監聽器的幫助類,擁有Set<ApplicationListener<?>>屬性
*/
private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
/**
* ListenerRetriever緩存
* key:ListenerCacheKey value:ListenerRetriever
*/
final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
// 添加spring監聽器到ListenerRetriever的applicationListeners集合中
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
// 移除監聽器
public void removeApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
// 移除所有監聽器
public void removeAllListeners() {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.clear();
this.defaultRetriever.applicationListenerBeans.clear();
this.retrieverCache.clear();
}
}
// 利用defaultRetriever得到所有的監聽器
protected Collection<ApplicationListener<?>> getApplicationListeners() {
synchronized (this.retrievalMutex) {
return this.defaultRetriever.getApplicationListeners();
}
}
根據上面代碼,大家注意到了AbstractApplicationEventMulticaster的增加,刪除和後去listeners是委託給其內部類ListenerRetriever去獲取的,因爲ListenerRetriever內部維護了監聽器的集合Set<ApplicationListener<?>>。下面看看ListenerRetriever這個內部類關鍵代碼:
private class ListenerRetriever {
/**
* 監聽器集合
*/
public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
public final Set<String> applicationListenerBeans = new LinkedHashSet<>();
private final boolean preFiltered;
public ListenerRetriever(boolean preFiltered) {
this.preFiltered = preFiltered;
}
/**
* 獲取所有的spring監聽器
* @return
*/
public Collection<ApplicationListener<?>> getApplicationListeners() {
List<ApplicationListener<?>> allListeners = new ArrayList<>(
this.applicationListeners.size() + this.applicationListenerBeans.size());
allListeners.addAll(this.applicationListeners);
if (!this.applicationListenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : this.applicationListenerBeans) {
try {
ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (this.preFiltered || !allListeners.contains(listener)) {
allListeners.add(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
if (!this.preFiltered || !this.applicationListenerBeans.isEmpty()) {
AnnotationAwareOrderComparator.sort(allListeners);
}
return allListeners;
}
}
下面再來看下承擔廣播事件的SimpleApplicationEventMulticaster類的關鍵代碼:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// 執行廣播異步事件的線程
@Nullable
private Executor taskExecutor;
// 廣播異步事件的線程時出現異常時的處理器
@Nullable
private ErrorHandler errorHandler;
/**
* Create a new SimpleApplicationEventMulticaster.
*/
public SimpleApplicationEventMulticaster() {
}
@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));
// 獲取執行異步任務的線程池,這裏異步要外部指定一個線程池,注入進來
Executor executor = getTaskExecutor();
// 遍歷每一個spring事件監聽器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 若外部指定的線程池不爲null,則異步廣播事件
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
// executor爲空,則單線程同步廣播事件
else {
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
// errorHandler不爲空的情況下,則會進入try...catch..代碼塊,這裏會對異步廣播事件發生的異常進行處理
if (errorHandler != null) {
try {
// 這裏真正執行廣播事件的邏輯
doInvokeListener(listener, event);
}
catch (Throwable err) {
// 處理異常
errorHandler.handleError(err);
}
}
// errorHandler爲空的情況下,則不對出現的異常進行處理
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 回調監聽器onApplicationEvent方法,執行監聽邏輯
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;
}
}
}
}
SimpleApplicationEventMulticaster是ApplicationEventMulticaster的實現類,承擔廣播所有事件給註冊的spring監聽器, 讓監聽器自己去決定哪些事件是自己感興趣的,監聽器們將會執行instanof來判斷是否是自己感興趣的事件。默認情況下,所有監聽器將會在調用線程中即單線程中同步阻塞執行,因此,若監聽器數量過多或某個監聽器執行時間過長 這將會導致spring容器啓動時間過長。不過SimpleApplicationEventMulticaster也提供了異步廣播時間的功能,通過taskExecutor來獲取線程池,然後多線程廣播事件,此外其還維護了一個errorHandler對象屬性,異常處理器,errorHandler主要用來當異步廣播事件時,若監聽器執行異常時,此時利用其來處理catch住的異常。
2.4 ApplicationEventPublisher
同樣,先來看下下面的類關係圖
可以看出所有Spring容器的父類接口ApplicationContext繼承了ApplicationEventPublisher這個接口,因此spring容器一般是具有廣播事件的功能。
下面來看下ApplicationEventPublisher的接口類代碼:
@FunctionalInterface
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
this.publishEvent((Object)event);
}
void publishEvent(Object event);
}
該接口封裝了發佈事件的公共方法,作爲ApplicationContext的超級接口,同事也是委託ApplicationEventMulticaster完成事件發佈。
下面再來看下Spring容器實現了ApplicationEventPublisher接口後是如何來發布事件的,此時得先來看下spring容器的父類接口ApplicationContext,因爲該接口繼承了ApplicationEventPublisher接口,因此讓spring容器具有了發佈事件的功能。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// 省略接口方法
}
那麼spring容器是如何來發布事件的呢?前面已經講過ApplicationEventMulticaster接口,沒錯,spring容器context正是委託其來實現發佈事件的功能。因爲AbstractApplicationContext實現了ConfigurableApplicationContext接口,通過該接口最終實現了ApplicationEventPublisher接口,spring容器發佈事件的方法封裝在AbstractApplicationContext的publishEvent方法中,
下面直接看下相關代碼:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
/**
* 父類context
*/
@Nullable
private ApplicationContext parent;
/**
* 在multicaster setup前,發佈事件
*/
@Nullable
private Set<ApplicationEvent> earlyApplicationEvents;
// 發佈事件給所有事件監聽器,
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// 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);
}
}
}
}
最後,弄清楚該源碼機制後,自己再動手實操一下,推薦閱讀下面的實操文章:
小結:這篇文章是本人第二篇源碼解析的文章,寫作速度仍然很慢,希望以後思路捋清楚後能快點寫完,加油。
參考: