Spring中事件發(fā)布機(jī)制及流程詳解
一、角色
事件類(lèi)
ApplicationEvent:定義事件類(lèi)型
|------ApplicationContextEvent:ApplicationContext引發(fā)的事件的基類(lèi)。
|------ContextClosedEvent:容器關(guān)閉事件
|------ContextRefreshedEvent:容器刷新事件
事件發(fā)布者
ApplicationEventPublisher:將應(yīng)用程序事件通知此應(yīng)用程序注冊(cè)的所有偵聽(tīng)器。
事件監(jiān)聽(tīng)者
ApplicationListener:由應(yīng)用程序事件偵聽(tīng)器實(shí)現(xiàn)的接口。
事件廣播器
ApplicationEventMulticaster:
|------AbstractApplicationEventMulticaster:提供了基本的偵聽(tīng)器注冊(cè)功能
|------SimpleApplicationEventMulticaster:實(shí)現(xiàn)事件通知具體方式
二、角色負(fù)責(zé)的功能
事件廣播器
ApplicationEventMulticaster接口
定義規(guī)范:
- 把監(jiān)聽(tīng)者加入集合
- 把監(jiān)聽(tīng)者移出集合
- 事件通知
// 把事件事件監(jiān)聽(tīng)者加入集合 void addApplicationListener(ApplicationListener<?> listener); // 把事件事件監(jiān)聽(tīng)者加入集合 void removeApplicationListener(ApplicationListener<?> listener); /** * 最終推送時(shí)間消息也會(huì)經(jīng)過(guò)這個(gè)接口方法來(lái)處理誰(shuí)該接收事件 * * @param event */ void multicastEvent(ApplicationEvent event);
AbstractApplicationEventMulticaster抽象類(lèi) 實(shí)現(xiàn)了:
- 創(chuàng)建集合用于存儲(chǔ)事件監(jiān)聽(tīng)者(Listener)
- 實(shí)現(xiàn)將事件監(jiān)聽(tīng)者(Listener)添加和移出集合的方法
- 實(shí)現(xiàn)將符合事件的監(jiān)聽(tīng)者添加入新建的集合并返回
- 拿出集合中所有的監(jiān)聽(tīng)者,根據(jù)要發(fā)生的事件判斷,該監(jiān)聽(tīng)者是否感興趣
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware { // 存放所有ApplicationListener的集合 public final LinkedHashSet<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet(); /** * 方法主要是摘取符合廣播事件中的監(jiān)聽(tīng)處理器,具體過(guò)濾動(dòng)作在 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)聽(tīng)器是否對(duì)該事件感興趣 * 主要包括對(duì) Cglib、Simple 不同實(shí)例化需要獲取目標(biāo) * Class,Cglib 代理類(lèi)需要獲取父類(lèi)的 Class,普通實(shí)例化的不需要。接下來(lái)就是通過(guò) * 提取接口和對(duì)應(yīng)的 ParameterizedType 和 eventClassName,方便最后確認(rèn)是否為 * 子類(lèi)和父類(lèi)的關(guān)系,以此證明此事件歸這個(gè)符合的類(lèi)處理。 * @param applicationListener * @param event * @return */ private boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) { Class<? extends ApplicationListener> listenerClass = applicationListener.getClass(); // 按照 CglibSubclassingInstantiationStrategy、 // SimpleInstantiationStrategy 不同的實(shí)例化類(lèi)型,需要判斷后獲取目標(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 對(duì)象所表示的類(lèi)或接口與指定的 event.getClass() 參數(shù)所 // 示的類(lèi)或接口是否相同,或是否是其超類(lèi)或超接口。 // isAssignableFrom 是用來(lái)判斷子類(lèi)和父類(lèi)的關(guān)系的,或者接口的實(shí)現(xiàn)類(lèi)和接口的關(guān)系的, // 默認(rèn)所有的類(lèi)的終極父類(lèi)都是 Object。如果 A.isAssignableFrom(B)結(jié)果是 true,證明 B 可以轉(zhuǎn)換成 // 為 A,也就是 A 可以由 B 轉(zhuǎn)換而來(lái)。 return eventClassName.isAssignableFrom(event.getClass()); } ...... }
SimpleApplicationEventMulticaster類(lèi) 實(shí)現(xiàn)了:
- 實(shí)現(xiàn)了事件通知(具體細(xì)節(jié)由父類(lèi)完成)
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是對(duì)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 { ..... // 一開(kāi)始就創(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)聽(tīng)者
當(dāng)我們關(guān)心spring容器什么時(shí)候刷新,或者想在spring容器刷新的時(shí)候做一些事情。 監(jiān)聽(tīng)關(guān)心的事件,主要就是在ApplicationListener中寫(xiě)對(duì)應(yīng)的事件。 spring容器在刷新完容器,就會(huì)調(diào)用該方法。
public class ContextRefreshedEventListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println("刷新事件(容器刷新完成):" + this.getClass().getName()); } }
三、使用spring中的事件機(jī)制
1.寫(xiě)一個(gè)事件類(lèi)(暫定我們關(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.寫(xiě)對(duì)應(yīng)的監(jiān)聽(tīng)者實(shí)現(xiàn)就可以了
public class CustomEventListener implements ApplicationListener<CustomEvent> { @Override public void onApplicationEvent(CustomEvent event) { System.out.println("收到:" + event.getSource() + "消息;時(shí)間:" + new Date()); System.out.println("消息:" + event.getId() + ":" + event.getMessage()); } }
四、整體流程
到此這篇關(guān)于Spring中事件發(fā)布機(jī)制及流程詳解的文章就介紹到這了,更多相關(guān)Spring事件發(fā)布機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring中的事件發(fā)布機(jī)制原理解析
- Spring的事件發(fā)布與監(jiān)聽(tīng)方式案例講解
- SpringBoot事件發(fā)布與監(jiān)聽(tīng)超詳細(xì)講解
- Spring事件發(fā)布監(jiān)聽(tīng),順序監(jiān)聽(tīng),異步監(jiān)聽(tīng)方式
- SpringBoot事件發(fā)布和監(jiān)聽(tīng)詳解
- 詳解Spring事件發(fā)布與監(jiān)聽(tīng)機(jī)制
- 解析Spring事件發(fā)布與監(jiān)聽(tīng)機(jī)制
- 詳解基于Spring Data的領(lǐng)域事件發(fā)布
相關(guān)文章
一文總結(jié)RabbitMQ中的消息確認(rèn)機(jī)制
RabbitMQ消息確認(rèn)機(jī)制指的是在消息傳遞過(guò)程中,發(fā)送方發(fā)送消息后,接收方需要對(duì)消息進(jìn)行確認(rèn),以確保消息被正確地接收和處理,本文為大家整理了RabbitMQ中的消息確認(rèn)機(jī)制,需要的可以參考一下2023-06-06解決Feign配置RequestContextHolder.getRequestAttributes()為null的問(wèn)題
這篇文章主要介紹了解決Feign配置RequestContextHolder.getRequestAttributes()為null的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01SpringCloud灰度發(fā)布的設(shè)計(jì)與實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringCloud灰度發(fā)布的設(shè)計(jì)與實(shí)現(xiàn)詳解,灰度從字面意思理解就是存在于黑與白之間的一個(gè)平滑過(guò)渡的區(qū)域,所以說(shuō)對(duì)于互聯(lián)網(wǎng)產(chǎn)品來(lái)說(shuō),上線(xiàn)和未上線(xiàn)就是黑與白之分,而實(shí)現(xiàn)未上線(xiàn)功能平穩(wěn)過(guò)渡的一種方式就叫做灰度發(fā)布,需要的朋友可以參考下2023-09-09IDEA修改生成jar包名字的兩種方法實(shí)現(xiàn)
本文主要介紹了IDEA修改生成jar包名字的兩種方法實(shí)現(xiàn),通過(guò)簡(jiǎn)單的步驟,您可以修改項(xiàng)目名稱(chēng)并在打包時(shí)使用新的名稱(chēng),具有一定的參考價(jià)值,感興趣的可以了解下2023-08-08springboot集成mybatisplus實(shí)例詳解
這篇文章主要介紹了springboot集成mybatisplus實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制
這篇文章主要介紹了詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制,ehcache提供了多種緩存策略,主要分為內(nèi)存和磁盤(pán)兩級(jí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01java實(shí)現(xiàn)系統(tǒng)托盤(pán)示例
桌面的系統(tǒng)托盤(pán)即當(dāng)程序最小化或者關(guān)閉按鈕程序并沒(méi)有退出,而是最小化在任務(wù)狀態(tài)區(qū)域,下面是使用java實(shí)現(xiàn)系統(tǒng)托盤(pán)示例2014-03-03