目錄結構
一個'叫床'的故事
之前講了深入Spring Events事件驅動模型,發現一些小夥伴不滿足於僅僅會用,還對事件驅動(Event Driven)的原理很感興趣,因此我們這篇文章就帶大家看下Spring事件驅動的核心原始碼。
對於事件驅動,你可以跟生活中的實際場景聯絡一下,就很容易理解了。
比如你去賓館開房,第二天早上6點要去趕飛機,就打電話給前臺,前臺記錄了你的房間號和叫醒時間,第二天早上,前臺就在指定的時間挨個給需要叫醒的顧客打電話,叫他們起床。
在這個故事裡,你就是一個監聽器,前臺就是一個廣播器,而早上6點提供叫醒服務就是一個事件。當這些早上六點被叫醒的監聽器們起床以後,有的去了機場,有的去了火車站,這就是對同一個事件不同的監聽器進行了不同的邏輯處理。
事件監聽器原始碼
你只要記住事件驅動中的三個角色,就很容易理解事件驅動的本質了,它們分別是:事件監聽器、事件廣播器和事件。
事件監聽器
我們的事件監聽器都實現了ApplicationListener
介面,這個介面中只有一個方法void onApplicationEvent(E event)
,用於處理監聽到的事件。至於監聽到事件以後怎麼辦,就是你的自由發揮餘地了。
事件廣播器
Spring通過事件廣播器ApplicationEventMulticaster
介面將事件分配給專門的監聽器。
ApplicationEventMulticaster
介面定義了3種方法:
- 新增監聽器:
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
實現了基本的新增和刪除監聽器的方法。
在實現類SimpleApplicationEventMulticaster
的原始碼裡,你可以看到事件是被ApplicationEventMulticaster
的multicastEvent(ApplicationEvent event)
方法傳送到每個已註冊的監聽器的。
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//根據eventType獲取所有該型別事件已註冊的監聽器集合並遍歷
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
//獲取執行緒池
Executor executor = getTaskExecutor();
if (executor != null) {
//如果有執行緒池則併發觸發監聽器的方法
executor.execute(() -> invokeListener(listener, event));
}
else {
//沒有執行緒池則依次執行
invokeListener(listener, event);
}
}
}
複製程式碼
到這裡你應該明白SpringEvents事件驅動的原理了:
以Spring容器為基礎,通過一個集合儲存事件與事件監聽器之間的對應關係(想想之前講的釋出者/訂閱者),然後當釋出事件的時候,根據事件型別獲取該事件所有的訂閱者,最後通過同步或非同步的方式通知到每個監聽器並執行監聽方法。
So easy !