Spring中事件發(fā)布機制及流程詳解
一、角色
事件類
ApplicationEvent:定義事件類型
|------ApplicationContextEvent:ApplicationContext引發(fā)的事件的基類。
|------ContextClosedEvent:容器關(guān)閉事件
|------ContextRefreshedEvent:容器刷新事件
事件發(fā)布者
ApplicationEventPublisher:將應(yīng)用程序事件通知此應(yīng)用程序注冊的所有偵聽器。
事件監(jiān)聽者
ApplicationListener:由應(yīng)用程序事件偵聽器實現(xiàn)的接口。
事件廣播器
ApplicationEventMulticaster:
|------AbstractApplicationEventMulticaster:提供了基本的偵聽器注冊功能
|------SimpleApplicationEventMulticaster:實現(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抽象類 實現(xiàn)了:
- 創(chuàng)建集合用于存儲事件監(jiān)聽者(Listener)
- 實現(xiàn)將事件監(jiān)聽者(Listener)添加和移出集合的方法
- 實現(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 不同實例化需要獲取目標(biāo) * Class,Cglib 代理類需要獲取父類的 Class,普通實例化的不需要。接下來就是通過 * 提取接口和對應(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 不同的實例化類型,需要判斷后獲取目標(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)系的,或者接口的實現(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類 實現(xiàn)了:
- 實現(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ā)布者
因為這邊事件都是ApplicationContextEvent,Application是對Spring應(yīng)用上下的管理。所以這邊充當(dāng)事件發(fā)布者的是AbstractApplicationContext。 AbstractApplicationContext 間接實現(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中的事件機制
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)聽者實現(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ā)布機制及流程詳解的文章就介紹到這了,更多相關(guān)Spring事件發(fā)布機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一文總結(jié)RabbitMQ中的消息確認(rèn)機制
RabbitMQ消息確認(rèn)機制指的是在消息傳遞過程中,發(fā)送方發(fā)送消息后,接收方需要對消息進行確認(rèn),以確保消息被正確地接收和處理,本文為大家整理了RabbitMQ中的消息確認(rèn)機制,需要的可以參考一下2023-06-06解決Feign配置RequestContextHolder.getRequestAttributes()為null的問題
這篇文章主要介紹了解決Feign配置RequestContextHolder.getRequestAttributes()為null的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01SpringCloud灰度發(fā)布的設(shè)計與實現(xiàn)詳解
這篇文章主要介紹了SpringCloud灰度發(fā)布的設(shè)計與實現(xiàn)詳解,灰度從字面意思理解就是存在于黑與白之間的一個平滑過渡的區(qū)域,所以說對于互聯(lián)網(wǎng)產(chǎn)品來說,上線和未上線就是黑與白之分,而實現(xiàn)未上線功能平穩(wěn)過渡的一種方式就叫做灰度發(fā)布,需要的朋友可以參考下2023-09-09詳解springboot整合ehcache實現(xiàn)緩存機制
這篇文章主要介紹了詳解springboot整合ehcache實現(xiàn)緩存機制,ehcache提供了多種緩存策略,主要分為內(nèi)存和磁盤兩級,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01