javascript
Spring5源码 - 11 Spring事件监听机制_源码篇
文章目錄
- pre
- 事件監聽機制的實現原理[觀察者模式]
- 事件 ApplicationEvent
- 事件監聽者 ApplicationEvent
- 事件發布者 ApplicationEventMulticaster (多播器)
- 工作流程
- 源碼解析
- 初始化事件多播器 initApplicationEventMulticaster()
- 注冊事件到多播器中 registerListeners()
- 事件發布publishEvent(默認同步)
pre
Spring5源碼 - 10 Spring事件監聽機制_應用篇
觀察者模式
說了應用,那我們來看下Spring的源碼是如何實現這種事件監聽機制的吧
事件監聽機制的實現原理[觀察者模式]
其實就是觀察者模式
事件 ApplicationEvent
事件監聽者 ApplicationEvent
相當于觀察者模式中的觀察者。監聽器監聽特定事件,并在內部定義了事件發生后的響應邏輯
事件發布者 ApplicationEventMulticaster (多播器)
相當于觀察者模式中的被觀察者/主題, 負責通知觀察者 對外提供發布事件和增刪事件監聽器的接口,維護事件和事件監聽器之間的映射關系,并在事件發生時負責通知相關監聽器
工作流程
Spring事件機制是觀察者模式的一種實現,但是除了發布者和監聽者者兩個角色之外,還有一個EventMultiCaster的角色負責把事件轉發給監聽者。
AnnotationConfigApplicationContext#publishEvent(ApplicationEvent event)將事件發送給了EventMultiCaster, 而后由EventMultiCaster注冊著所有的Listener,然后根據事件類型決定轉發給那個Listener。
源碼解析
debug走起,
Spring在ApplicationContext接口的抽象實現類AbstractApplicationContext中完成了事件體系的搭建。
AbstractApplicationContext擁有一個applicationEventMulticaster成員變量,applicationEventMulticaster提供了容器監聽器的注冊表。
還是進入到refresh方法中
refresh() -----> 直接看 initApplicationEventMulticaster() -----------> registerListeners() ---------> finishRefresh() 進入 ----> publishEvent(new ContextRefreshedEvent(this))
初始化事件多播器 initApplicationEventMulticaster()
protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();//判斷IOC容器中包含applicationEventMulticaster 事件多播器的Bean的nameif (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {/創建一個applicationEventMulticaster的bean放在IOC 容器中,bean的name 為applicationEventMulticasterthis.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isDebugEnabled()) {logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else { //容器中不包含一個beanName 為applicationEventMulticaster的多播器組件//創建一個SimpleApplicationEventMulticaster 多播器this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);//注冊到容器中beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isDebugEnabled()) {logger.debug("Unable to locate ApplicationEventMulticaster with name '" +APPLICATION_EVENT_MULTICASTER_BEAN_NAME +"': using default [" + this.applicationEventMulticaster + "]");}}}?一句話概括:我們可以在配置文件中為容器定義一個自定義的事件廣播器,只要實現ApplicationEventMulticaster就可以了,Spring會通過 反射的機制將其注冊成容器的事件廣播器,如果沒有找到配置的外部事件廣播器,Spring默認使用 SimpleApplicationEventMulticaster作為事件廣播器
注冊事件到多播器中 registerListeners()
protected void registerListeners() {//去容器中把applicationListener 撈取出來注冊到多播器上去(系統的)for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}//開發人員實現了ApplicationListener 的組件String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}//在這里之前,我們早期想發布的事件 由于沒有多播器沒有發布,在這里我們總算有了自己的多播器,可以在這里發布早期堆積的事件了. (早起發布事件,會自動發布,無需調用pubilish)Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (earlyEventsToProcess != null) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}一句話概括 : Spring根據反射機制,使用ListableBeanFactory的getBeansOfType方法,從BeanDefinitionRegistry中找出所有實現 org.springframework.context.ApplicationListener的Bean,將它們注冊為容器的事件監聽器,實際的操作就是將其添加到事件廣播器所提供的監聽器注冊表中。
事件發布publishEvent(默認同步)
org.springframework.context.support.AbstractApplicationContext#publishEvent(java.lang.Object, org.springframework.core.ResolvableType)進入 org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));//獲取到所有的監聽器for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {//看spring 容器中是否支持線程池 異步發送事件Executor executor = getTaskExecutor();if (executor != null) {executor.execute(new Runnable() {@Overridepublic void run() {invokeListener(listener, event);}});}else { //同步發送事件invokeListener(listener, event);}}}支持異步,默認同步 。
遍歷注冊的每個監聽器,并啟動來調用每個監聽器的onApplicationEvent方法。由于SimpleApplicationEventMulticaster的taskExecutor的實現類是SyncTaskExecutor,因此,事件監聽器對事件的處理,是同步進行的。
來看看
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {//調用對于listener的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.isDebugEnabled()) {logger.debug("Non-matching event type for listener: " + listener, ex);}}else {throw ex;}}}就是調用 listener.onApplicationEvent(event);
總結
以上是生活随笔為你收集整理的Spring5源码 - 11 Spring事件监听机制_源码篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring5源码 - 10 Spri
- 下一篇: Spring5源码 - 12 Sprin