介紹
spring內部實現了一套事件傳播機制的,也是觀察者模式的實現
主要角色
- 事件
在spring中一般就是ApplicationEvent對象(這是一個抽象類而不是接口)。spring中的常見事件:
- ApplicationContextEvent:抽象類,ApplicationContext相關的事件。具體實現有:
- ContextClosedEvent
- ContextRefreshedEvent
- ContextStartedEvent
- ContextStoppedEvent
- SpringApplicationEvent:抽象類,SpringApplication相關的事件,在springboot的啓動過程中逐個發佈。具體實現有:
- ApplicationStartingEvent
- ApplicationEnvironmentPreparedEvent
- ApplicationFailedEvent
- ApplicationPreparedEvent
- ApplicationReadyEvent
- ServletRequestHandledEvent:RequestHandledEvent的子類,每次請求處理完成後會發布這個事件
- ApplicationContextEvent:抽象類,ApplicationContext相關的事件。具體實現有:
- 事件發佈(傳播)器
事件發佈器,在spring中對應ApplicationEventPublisher接口,其實現類就是各個ApplicationContext實現。接口定義如下:
public interface ApplicationEventPublisher {
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
void publishEvent(Object event);
}
並沒有啥值得提的地方,唯一的方法就是發佈事件。
雖然ApplicationEventPublisher對應的角色是事件發佈器,但其實具體的事件傳播行爲以及對listener的管理其實是由ApplicationEventMulticaster實現的,接口定義:
public interface ApplicationEventMulticaster {
//管理listener相關的方法
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);
}
spring中,ApplicationEventMulticaster的內置實現類只有一個:SimpleApplicationEventMulticaster
- 監聽器
對應spring中的ApplicationListener。接口定義:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
響應事件或者說處理事件。有兩個子接口:
- GenericApplicationListener
接口定義:
public interface GenericApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {
//相對於ApplicationListener,推展了支持的事件類型
boolean supportsEventType(ResolvableType eventType);
boolean supportsSourceType(@Nullable Class<?> sourceType);
}
- SmartApplicationListener
雖然叫做Smart,好像很厲害,但是其實已經是過時了的接口,GenericApplicationListener就是其替代者
事件處理過程
以springboot啓動過程中,由SpringApplication發佈的第一個SpringApplicationEvent事件:ApplicationStartingEvent爲例:(對於ac直接發佈事件,一般是ac.publishEvent()方法,但其實內部也就是調用multicastEvent()方法)
SimpleApplicationEventMulticaster發佈事件的代碼如下:
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));//1
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {//2
Executor executor = getTaskExecutor();
//3
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
1. ResolvableType
是spring裏對java 類型的一種解析,封裝了某個 java.lang.reflect.Type的元數據,比如它的泛型、實現的接口、父類等等
2. getApplicationListeners(event, type)從管理的所有listener中選擇出可以響應這個事件的listener
其具體做法是:
- 遍歷所有的listener
- 將所有的listener處理成GenericApplicationListener,對於原來不是GenericApplicationListener的,就使用GenericApplicationListenerAdapter適配成GenericAL
- 根據GenericAL接口中的supportsEventType和supportsSourceType方法的返回確定改listener是否需要被調用
3. 調用滿足條件的listener
這裏涉及到SimpleApplicationEventMulticaster的兩個屬性:
- taskExecutor:如果不爲null,則對listener的調用會交由該線程池處理
- errorHandler:如果不爲null,則對listener調用過程中如果出現異常,會交由該ErrorHandler處理
怎麼在spring中註冊自己的監聽器
方法有3種:
- 通過在application.properties中配置context.listener.classes屬性,值是具體的類名,多個值以逗號分隔
- 任意實現了ApplicationListener並註冊到ApplicationListener中的bean都會被自動檢測到
- 在任意bean的方法上加上@EventListener註解,也可以
怎麼發佈事件
我們知道spring中有個Aware標記接口,也有很多像ApplicationContextAware/BeanFactoryAware/EnvironmentAware/ResourceLoaderAware等這個接口的子接口,只要實現了當中的XXAware接口,在bean實例時,就會通過BeanPostProcessor把對應的XX注入到bean中。在spring中事件發佈能力由ApplicationEventMulticaster 接口定義,所以可以通過讓bean實現ApplicationEventPublisherAware接口,讓bean可以獲取ApplicationEventPublisher的引用,從而具備發佈事件的能力。
其實這些實現XXAware接口的bean,只要這個ApplicationContext接口實現了XX接口,得到的引用其實就是ApplicationContext的實現,所以實現ApplicationEventPublisherAware接口的bean,得到的其實也是ApplicationContext的引用
springboot啓動過程中自動註冊的10個監聽器
1. 怎麼個自動法
其實也沒啥了不得的東西。跟springboot自動裝配的那些bean的機制一樣:
- 讀取classpath下所有路徑爲META-INF/spring.factories文件
- 找到當中key爲org.springframework.context.ApplicationListener的所有值
- 實例化這些value對應的類,並作爲ApplicationListener註冊到ApplicationContext中
2.這10個listener各自的作用
- BackgroundPreinitializer
新建後臺進程,進行一些比較耗時的bean的初始化 - ClearCacheApplicationListener
context加載完成後清理緩存 - ParentContextCloserApplicationListener
當父ApplicationContext(如果有的話)關閉後,也把當前的AC關閉 - FileEncodingApplicationListener
spring.mandatory-file-encoding這個屬性的校驗,如果存在的話看他是否和JDK的一致,不一致就報錯 - AnsiOutputAL
根據spring.output.ansi.enabled屬性配置AnsiOutput - ConfigFileApplicationListener
這個就厲害了,spring之所以會自動讀取classpath下的application.properties/yml,就是這個listener的實現。默認情況下會從:classpath:/classpath:config/等中加載application.properties/application.yml.也會基於active profile載入額外的文件.路徑或者文件名可以通過spring.config.name/spring.config.location配置 - DelegatingApplicationListener
如果通過context.listener.classes屬性往AC中加入了自定義的ApplicationListener,這個DelegatingAL就會把事件傳播給這些自定義的實現 - ClasspathLoggingApplicationListener
僅響應ApplicationEnvironmentPreparedEvent/ApplicationFailedEvent,通過以debug級別打印thread context class loader - LoggingApplicationListener
配置LoggingSystem.如果environment中有logging.config配置,則會用於引導LoggingSystem.並且,日誌級別可以通過logging.level.*來配置.默認情況下,僅console會有日誌輸出.如果需要日誌文件,可以通過logging.path或者logging.file來配置 - LiquibaseServiceLocatorApplicationListener
結語
(水平有限,最近在看spring源碼,分享學習過程,希望對各位有點微小的幫助。
如有錯誤,請指正~)