Spring中事件發(fā)布機(jī)制及流程詳解
一、角色

事件類
ApplicationEvent:定義事件類型
|------ApplicationContextEvent:ApplicationContext引發(fā)的事件的基類。
|------ContextClosedEvent:容器關(guān)閉事件
|------ContextRefreshedEvent:容器刷新事件
事件發(fā)布者
ApplicationEventPublisher:將應(yīng)用程序事件通知此應(yīng)用程序注冊的所有偵聽器。
事件監(jiān)聽者
ApplicationListener:由應(yīng)用程序事件偵聽器實(shí)現(xiàn)的接口。
事件廣播器
ApplicationEventMulticaster:
|------AbstractApplicationEventMulticaster:提供了基本的偵聽器注冊功能
|------SimpleApplicationEventMulticaster:實(shí)現(xiàn)事件通知具體方式
二、角色負(fù)責(zé)的功能
事件廣播器
ApplicationEventMulticaster接口
定義規(guī)范:
- 把監(jiān)聽者加入集合
- 把監(jiān)聽者移出集合
- 事件通知
// 把事件事件監(jiān)聽者加入集合
void addApplicationListener(ApplicationListener<?> listener);
// 把事件事件監(jiān)聽者加入集合
void removeApplicationListener(ApplicationListener<?> listener);
/**
* 最終推送時間消息也會經(jīng)過這個接口方法來處理誰該接收事件
*
* @param event
*/
void multicastEvent(ApplicationEvent event);
AbstractApplicationEventMulticaster抽象類 實(shí)現(xiàn)了:
- 創(chuàng)建集合用于存儲事件監(jiān)聽者(Listener)
- 實(shí)現(xiàn)將事件監(jiān)聽者(Listener)添加和移出集合的方法
- 實(shí)現(xiàn)將符合事件的監(jiān)聽者添加入新建的集合并返回
- 拿出集合中所有的監(jiān)聽者,根據(jù)要發(fā)生的事件判斷,該監(jiān)聽者是否感興趣
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
// 存放所有ApplicationListener的集合
public final LinkedHashSet<ApplicationListener<ApplicationEvent>>
applicationListeners = new LinkedHashSet();
/**
* 方法主要是摘取符合廣播事件中的監(jiān)聽處理器,具體過濾動作在 supportsEvent 方法中。
* @param event
* @return
*/
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event){
LinkedList<ApplicationListener> allListeners = new LinkedList<>();
for (ApplicationListener<ApplicationEvent> listener : applicationListeners){
if(supportsEvent(listener, event)) allListeners.add(listener);
}
return allListeners;
}
/**
* 監(jiān)聽器是否對該事件感興趣
* 主要包括對 Cglib、Simple 不同實(shí)例化需要獲取目標(biāo)
* Class,Cglib 代理類需要獲取父類的 Class,普通實(shí)例化的不需要。接下來就是通過
* 提取接口和對應(yīng)的 ParameterizedType 和 eventClassName,方便最后確認(rèn)是否為
* 子類和父類的關(guān)系,以此證明此事件歸這個符合的類處理。
* @param applicationListener
* @param event
* @return
*/
private boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
// 按照 CglibSubclassingInstantiationStrategy、
// SimpleInstantiationStrategy 不同的實(shí)例化類型,需要判斷后獲取目標(biāo) class
Class<?> targetClass = ClassUtils.isCglibProxyClass(listenerClass) ?
listenerClass.getSuperclass() : listenerClass;
Type genericInterface = targetClass.getGenericInterfaces()[0];
Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
String className = actualTypeArgument.getTypeName();
Class<?> eventClassName;
try {
eventClassName = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new BeansException("wrong event class name: " + className);
}
// 判定此 eventClassName 對象所表示的類或接口與指定的 event.getClass() 參數(shù)所
// 示的類或接口是否相同,或是否是其超類或超接口。
// isAssignableFrom 是用來判斷子類和父類的關(guān)系的,或者接口的實(shí)現(xiàn)類和接口的關(guān)系的,
// 默認(rèn)所有的類的終極父類都是 Object。如果 A.isAssignableFrom(B)結(jié)果是 true,證明 B 可以轉(zhuǎn)換成
// 為 A,也就是 A 可以由 B 轉(zhuǎn)換而來。
return eventClassName.isAssignableFrom(event.getClass());
}
......
}
SimpleApplicationEventMulticaster類 實(shí)現(xiàn)了:
- 實(shí)現(xiàn)了事件通知(具體細(xì)節(jié)由父類完成)
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
@Override
public void multicastEvent(ApplicationEvent event) {
for(final ApplicationListener listener : getApplicationListeners(event)){
listener.onApplicationEvent(event);
}
}
.......
}
事件發(fā)布者
因?yàn)檫@邊事件都是ApplicationContextEvent,Application是對Spring應(yīng)用上下的管理。所以這邊充當(dāng)事件發(fā)布者的是AbstractApplicationContext。 AbstractApplicationContext 間接實(shí)現(xiàn)ApplicationEventPublisher
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
private ApplicationEventMulticaster applicationEventMulticaster;
@Override
public void refresh() throws BeansException {
.....
// 一開始就創(chuàng)建了事件廣播器
// 6. 初始化事件發(fā)布者
initApplicationEventMulticaster();
.......
// 9. 發(fā)布容器刷新完成事件(發(fā)布是容器刷新事件)
finishRefresh();
}
// 創(chuàng)建事件廣播器
private void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
private void finishRefresh() {
publishEvent(new ContextRefreshedEvent(this));
}
@Override
public void publishEvent(ApplicationEvent event) {
applicationEventMulticaster.multicastEvent(event);
}
.......
}
事件監(jiān)聽者
當(dāng)我們關(guān)心spring容器什么時候刷新,或者想在spring容器刷新的時候做一些事情。 監(jiān)聽關(guān)心的事件,主要就是在ApplicationListener中寫對應(yīng)的事件。 spring容器在刷新完容器,就會調(diào)用該方法。
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("刷新事件(容器刷新完成):" + this.getClass().getName());
}
}
三、使用spring中的事件機(jī)制
1.寫一個事件類(暫定我們關(guān)心的是application上下文的事件)
public class CustomEvent extends ApplicationContextEvent {
private Long id;
private String message;
/**
* Constructs a prototypical Event.
*
* @param source The object on which the Event initially occurred.
* @throws IllegalArgumentException if source is null.
*/
public CustomEvent(Object source,Long id, String message) {
super(source);
this.id = id;
this.message = message;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2.事件發(fā)布者
@Test
public void test_event(){
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext("classpath:spring.xml");
applicationContext.publishEvent(new CustomEvent(applicationContext, 101912455552221L, "事件發(fā)布成功!"));
//applicationContext.registerShutdownHook();
}
3.寫對應(yīng)的監(jiān)聽者實(shí)現(xiàn)就可以了
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("收到:" + event.getSource() + "消息;時間:" + new Date());
System.out.println("消息:" + event.getId() + ":" + event.getMessage());
}
}
四、整體流程

到此這篇關(guān)于Spring中事件發(fā)布機(jī)制及流程詳解的文章就介紹到這了,更多相關(guān)Spring事件發(fā)布機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringCloud Hystrix-Dashboard儀表盤的實(shí)現(xiàn)
這篇文章主要介紹了SpringCloud Hystrix-Dashboard儀表盤的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
gradle配置國內(nèi)鏡像的實(shí)現(xiàn)
這篇文章主要介紹了gradle配置國內(nèi)鏡像的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Java向MySQL添加中文數(shù)據(jù)數(shù)據(jù)庫顯示亂碼的解決方案
在用springboot做項(xiàng)目時,由于重新安裝了本地Mysql數(shù)據(jù)庫(5.7版本)在前臺向數(shù)據(jù)庫插入和更新數(shù)據(jù)可的時候,涉及中文的時候在數(shù)據(jù)庫一直顯示異常,所以本文給大家介紹了相關(guān)的解決方案,需要的朋友可以參考下2024-02-02
IntelliJIDEA中實(shí)現(xiàn)SpringBoot多實(shí)例運(yùn)行的兩種方式
在微服務(wù)開發(fā)中,經(jīng)常需要同時啟動多個服務(wù)實(shí)例進(jìn)行測試或模擬集群環(huán)境,?IntelliJ?IDEA?作為Java開發(fā)者常用工具,提供了靈活的多實(shí)例啟動支持,本文將詳細(xì)介紹如何通過修改配置?和批量啟動?兩種方式實(shí)現(xiàn)SpringBoot多實(shí)例運(yùn)行,并解決常見問題,需要的朋友可以參考下2025-03-03
jcl與jul?log4j1?log4j2?logback日志系統(tǒng)機(jī)制及集成原理
這篇文章主要介紹了jcl與jul?log4j1?log4j2?logback的集成原理,Apache?Commons-logging?通用日志框架與日志系統(tǒng)的機(jī)制,有需要的朋友可以借鑒參考下2022-03-03
java實(shí)現(xiàn)短信驗(yàn)證碼5分鐘有效時間
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)短信驗(yàn)證碼5分鐘有效時間,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-07-07
Nacos配置中心與本地代碼工程配置文件之間的優(yōu)先級關(guān)系詳解
本文介紹了Spring Cloud生態(tài)中配置加載原理,強(qiáng)調(diào)Nacos遠(yuǎn)程配置優(yōu)先級高于本地`application.yml`但低于命令行和環(huán)境變量,覆蓋了多環(huán)境配置、動態(tài)刷新配置及安全配置外置等應(yīng)用場景,對比了Nacos配置中心與本地配置文件的優(yōu)缺點(diǎn),并給出最佳實(shí)踐建議2026-04-04

