微信公衆號:IT學習筆記
學習更多源碼知識,歡迎關注。html
注意:該源碼分析對應版本爲spring5.1.xjava
本篇開始分析Spring的事件機制源碼,由於Spring的事件機制實質是觀察者(發佈訂閱)模式的實現,所以要想搞清楚Spring的事件機制,所以得知道觀察者模式是什麼。同時推薦閱讀下這篇文章的前奏文章,對於理解spring的事件機制很是有幫助,推薦我都另外一篇翻譯的博文:web
模仿Spring事件機制實現自定義事件驅動編程--Spring的事件機制源碼分析(一)spring
在開始正題前,先聊聊研究源碼的感覺:研究源碼前那麼必須先搞清楚類與類之間的關係,好比某個接口有哪些實現類,某個父類有哪些子類,子類與子類之間的關係,這些類之間的關係捋清楚了,那麼再下手研究源碼就容易不少。總之不能一會兒就進入源碼的某個細節,這樣子就會形成只見冰山一角而看不到全貌的感受。編程
好了,下面開始進入正題,開始學習Spring的事件機制。由於編碼通常都是面向接口編程,那麼咱們先從事件機制的相關接口或抽象類開始分析。緩存
Spring事件機制涉及的重要的類主要有如下四個:bash
事件相關的主要接口類上面已經介紹完畢,下面來看下每一個接口及其子類之間的關係。微信
首先看下類圖以下:多線程
圖1mvc
其接口代碼以下:
// 事件抽象類,這個是全部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的有四個子類,以下:
以上四個事件就是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);
}
}複製代碼
@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接口的具體實現類太多,所以就不貼類關係圖了。
首先看下類圖,
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住的異常。
一樣,先來看下下面的類關係圖
能夠看出全部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);
}
}
}
}複製代碼
最後,弄清楚該源碼機制後,本身再動手實操一下,推薦閱讀下面的實操文章:
小結:這篇文章是本人第二篇源碼解析的文章,寫做速度仍然很慢,但願之後思路捋清楚後能快點寫完,加油。
參考: