Spring 與 Spring Boot 中的事件機(jī)制
點(diǎn)擊上方藍(lán)色“程序猿DD”,選擇“設(shè)為星標(biāo)”
回復(fù)“資源”獲取獨(dú)家整理的學(xué)習(xí)資料!

作者 | 溫安適
引言
spring事件機(jī)制,有3個(gè)核心部分,事件,監(jiān)聽方式,廣播器,下面我們分別介紹。
Spring事件
spring的事件的API對應(yīng)ApplicationEvent。它繼承了ava.util.EventObject。顯示調(diào)用父類構(gòu)造器傳遞事件源。
public?abstract?class?ApplicationEvent?extends?EventObject?{
?????///省略其他代碼
??public?ApplicationEvent(Object?source)?{
??super(source);
??this.timestamp?=?System.currentTimeMillis();
??}
???????//省略其他代碼
}
Spring內(nèi)置事件
| 事件名 | 注釋 |
|---|---|
| ContextRefreshedEvent | Spring應(yīng)用上下文就緒事件 |
| ContextStartedEvent | Spring應(yīng)用上下文啟動(dòng)事件 |
| ContextStopedEvent | Spring應(yīng)用上下文停止事件 |
| ContextClosedEvent | Spring應(yīng)用上下文關(guān)閉事件 |
允許泛型事件自定義,如果有興趣可以參看:org.springframework.context.PayloadApplicationEvent
Spring事件監(jiān)聽手段
2種監(jiān)聽手段
\1. 實(shí)現(xiàn)ApplicationListener接口 或 @EventListener,可監(jiān)聽1到多種事件,支持泛型事件
\2. @EventListener方法上@Async,可使用@EventListener方法異步化,但是被注解的方法的返回值應(yīng)該為void,其實(shí)返回值沒有意義。
表@EventListener的同步與異步區(qū)別
| 方法類型 | 訪問修飾符 | 返回類型 | 參數(shù)數(shù)量 | 參數(shù)類型 | 備注 |
|---|---|---|---|---|---|
| 同步 | public | 任意類型 | 0或1 | 監(jiān)聽事件類型或其子類 | 會(huì)將返回值作為事件向后傳播 |
| 異步 | public | void | 0或1 | 監(jiān)聽事件類型或其子類 | 如果出錯(cuò)不會(huì)傳播給調(diào)用者。不會(huì)向后傳播事件 |
@EventListener原理
找入口

EventListenerMethodProcessor 就是處理@EventListener注解的入口類
找主要方法
查看 EventListenerMethodProcessor 的類注釋,簡要翻譯如下:
“1.將@EventListener方法轉(zhuǎn)換為**ApplicationListener示例2.實(shí)現(xiàn)BeanFactoryPostProcessor用于檢索EventListenerFactory避免AOP增強(qiáng),EventListenerFactory
在查看, EventListenerMethodProcessor的類圖

ApplicationContextAware 用于注入ApplicationContext。
BeanFactoryPostProcessor根據(jù)類注釋可知用于獲取EventListenerFactory。
這里最需要關(guān)注的應(yīng)該是SmartInitializingSingleton#afterSingletonsInstantiated方法。
查看該方法的注釋
public?interface?SmartInitializingSingleton?{
???/**
????*?預(yù)實(shí)例化完成之后調(diào)用,保證所有常規(guī)單例Bean創(chuàng)建完畢
????*?調(diào)用ListableBeanFactory#getBeansOfType沒有任何副作用
????*?注意:?
????*?對于延遲加載的單例Bean,不會(huì)觸發(fā)這個(gè)回調(diào)。
????*?并且其他作用域的Bean,也不會(huì)觸發(fā)這個(gè)回調(diào)。
????*?謹(jǐn)慎使用,應(yīng)僅用于引導(dǎo)功能。
????*/
???void?afterSingletonsInstantiated();
}
afterSingletonsInstantiated 從方法注釋上可以看出,這個(gè)方法可以用于引導(dǎo)功能。
查看源碼EventListenerMethodProcessor ,邏輯就是找BeanName和Bean對應(yīng)的Type,具體邏輯委托給processBean,下面是processBean的源碼
public?class?EventListenerMethodProcessor?{
????//省略其他部分
private?void?processBean(final?String?beanName,?final?Class>?targetType)?{
???if?(!this.nonAnnotatedClasses.contains(targetType)?&&
?????????!targetType.getName().startsWith("java")?&&
?????????!isSpringContainerClass(targetType))?{
??????Map?annotatedMethods?=?null;
??????try?{
??????????//找出所有EventListener注解的方法
?????????annotatedMethods?=?MethodIntrospector.selectMethods(targetType,
???????????????(MethodIntrospector.MetadataLookup)?method?->
?????????????????????AnnotatedElementUtils.findMergedAnnotation(method,?EventListener.class));
??????}
??????catch?(Throwable?ex)?{
?????????//?An?unresolvable?type?in?a?method?signature,?probably?from?a?lazy?bean?-?let's?ignore?it.
?????????if?(logger.isDebugEnabled())?{
????????????logger.debug("Could?not?resolve?methods?for?bean?with?name?'"?+?beanName?+?"'",?ex);
?????????}
??????}
??????if?(CollectionUtils.isEmpty(annotatedMethods))?{
?????????this.nonAnnotatedClasses.add(targetType);
?????????if?(logger.isTraceEnabled())?{
????????????logger.trace("No?@EventListener?annotations?found?on?bean?class:?"?+?targetType.getName());
?????????}
??????}
??????else?{
?????????//?Non-empty?set?of?methods
?????????ConfigurableApplicationContext?context?=?this.applicationContext;
?????????Assert.state(context?!=?null,?"No?ApplicationContext?set");
?????????List?factories?=?this.eventListenerFactories;
?????????Assert.state(factories?!=?null,?"EventListenerFactory?List?not?initialized");
?????????for?(Method?method?:?annotatedMethods.keySet())?{
????????????for?(EventListenerFactory?factory?:?factories)?{
???????????????if?(factory.supportsMethod(method))?{
??????????????????Method?methodToUse?=?AopUtils.selectInvocableMethod(method,?context.getType(beanName));
?????????????????//通過EventListenerFactory轉(zhuǎn)換為ApplicationListenerMethodAdapter
???????????????????ApplicationListener>?applicationListener?=
????????????????????????factory.createApplicationListener(beanName,?targetType,?methodToUse);
??????????????????if?(applicationListener?instanceof?ApplicationListenerMethodAdapter)?{
?????????????????????((ApplicationListenerMethodAdapter)?applicationListener).init(context,?this.evaluator);
??????????????????}
??????????????????//將該事件監(jiān)聽器注冊到應(yīng)用上下文中。
??????????????????context.addApplicationListener(applicationListener);
??????????????????break;
???????????????}
????????????}
?????????}
?????????if?(logger.isDebugEnabled())?{
????????????logger.debug(annotatedMethods.size()?+?"?@EventListener?methods?processed?on?bean?'"?+
??????????????????beanName?+?"':?"?+?annotatedMethods);
?????????}
??????}
???}
}
}
AopUtils.selectInvocableMethod 是不允許訪問,私有方法,靜態(tài)方法,代理的方法,也就印證了 @EventListener必須用public修飾
概要邏輯
1.這個(gè)方法的邏輯就是將@EventListener的方法,
2.通過 EventListenerFactory轉(zhuǎn)換為ApplicationListenerMethodAdapter,
3.該事件監(jiān)聽器注冊上線文中。
@EventListener總結(jié)
EventListenerMethodProcessor 是@EventListener的生命周期處理器,實(shí)現(xiàn)了 SmartInitializingSingleton接口的afterSingletonsInstantiated 方法,進(jìn)行了:
這個(gè)方法的邏輯就是將@EventListener的方法, 通過EventListenerFactory轉(zhuǎn)換為ApplicationListenerMethodAdapter, 該事件監(jiān)聽器注冊上線文中。
DefaultEventListenerFactory是@EventListener方法與ApplicationListener的適配工廠
ApplicationListenerMethodAdapter為適配類。
Spring的廣播器
廣播器為ApplicationEventMulticaster,它的默認(rèn)實(shí)現(xiàn)為SimpleApplicationEventMulticaster
它主要有2個(gè)責(zé)任,維護(hù)ApplicationListener關(guān)聯(lián)關(guān)系這個(gè)比較簡單,我們關(guān)注下廣播消息。
@Override
public?void?multicastEvent(final?ApplicationEvent?event,?@Nullable?ResolvableType?eventType)?{
???ResolvableType?type?=?(eventType?!=?null???eventType?:?resolveDefaultEventType(event));
???Executor?executor?=?getTaskExecutor();
???for?(ApplicationListener>?listener?:?getApplicationListeners(event,?type))?{
??????if?(executor?!=?null)?{
?????????executor.execute(()?->?invokeListener(listener,?event));
??????}
??????else?{
?????????invokeListener(listener,?event);
??????}
???}
}
調(diào)用getApplicationListeners,遍歷調(diào)用onApplicationEvent(ApplicationEvent)。
查看getApplicationListeners方法在其父類 AbstractApplicationEventMulticaster中。
protected?Collection>?getApplicationListeners(
??????ApplicationEvent?event,?ResolvableType?eventType)?{
???Object?source?=?event.getSource();
???Class>?sourceType?=?(source?!=?null???source.getClass()?:?null);
???ListenerCacheKey?cacheKey?=?new?ListenerCacheKey(eventType,?sourceType);
???//?Quick?check?for?existing?entry?on?ConcurrentHashMap...
???ListenerRetriever?retriever?=?this.retrieverCache.get(cacheKey);
???if?(retriever?!=?null)?{
??????return?retriever.getApplicationListeners();
???}
???if?(this.beanClassLoader?==?null?||
?????????(ClassUtils.isCacheSafe(event.getClass(),?this.beanClassLoader)?&&
???????????????(sourceType?==?null?||?ClassUtils.isCacheSafe(sourceType,?this.beanClassLoader))))?{
??????//?Fully?synchronized?building?and?caching?of?a?ListenerRetriever
??????synchronized?(this.retrievalMutex)?{
?????????retriever?=?this.retrieverCache.get(cacheKey);
?????????if?(retriever?!=?null)?{
????????????return?retriever.getApplicationListeners();
?????????}
?????????retriever?=?new?ListenerRetriever(true);
?????????Collection>?listeners?=
???????????????retrieveApplicationListeners(eventType,?sourceType,?retriever);
?????????this.retrieverCache.put(cacheKey,?retriever);
?????????return?listeners;
??????}
???}
???else?{
??????//?No?ListenerRetriever?caching?->?no?synchronization?necessary
??????return?retrieveApplicationListeners(eventType,?sourceType,?null);
???}
}
內(nèi)部維護(hù)一個(gè)final Map
ListenerCacheKey為eventType(對應(yīng)泛型或者事件類本身) 和sourceType(ApplicationEvent構(gòu)造器中的source),(對應(yīng)ApplicationEvent)。
SimpleApplicationEventMulticaster總結(jié):
SimpleApplicationEventMulticaster承擔(dān)2個(gè)職責(zé),關(guān)聯(lián)ApplicationListener,廣播ApplicationEvent。
SimpleApplicationEventMulticaster 內(nèi)部維護(hù)一個(gè)final Map
retrieverCache 維護(hù)事件類型與數(shù)據(jù)源的類型 ListenerCacheKey為eventType(對應(yīng)泛型或者事件類本身) 和sourceType(ApplicationEvent構(gòu)造器中的source)
ListenerRetriever是AbstractApplicationEventMulticaster的內(nèi)部類,對應(yīng)ApplicationListener集合
ApplicationEventMulticaster廣播事件,multicastEvent(ApplicationEvent)和multicastEvent(ApplicationEvent,ResolvableType)
內(nèi)部調(diào)用getApplicationListeners,遍歷調(diào)用onApplicationEvent(ApplicationEvent)
補(bǔ)充說明:
通過ApplicationEventPublisherAware獲得的ApplicationEventPublisher,是什么?
解決這個(gè),就需要查看ApplicationContextAwareProcessor#postProcessBeforeInitialization
內(nèi)部調(diào)用了 invokeAwareInterfaces方法,處理各種Aware接口的注入邏輯。
private?void?invokeAwareInterfaces(Object?bean)?{
???if?(bean?instanceof?EnvironmentAware)?{
??????((EnvironmentAware)?bean).setEnvironment(this.applicationContext.getEnvironment());
???}
???if?(bean?instanceof?EmbeddedValueResolverAware)?{
??????((EmbeddedValueResolverAware)?bean).setEmbeddedValueResolver(this.embeddedValueResolver);
???}
???if?(bean?instanceof?ResourceLoaderAware)?{
??????((ResourceLoaderAware)?bean).setResourceLoader(this.applicationContext);
???}
???if?(bean?instanceof?ApplicationEventPublisherAware)?{
??????((ApplicationEventPublisherAware)?bean).setApplicationEventPublisher(this.applicationContext);
???}
???if?(bean?instanceof?MessageSourceAware)?{
??????((MessageSourceAware)?bean).setMessageSource(this.applicationContext);
???}
???if?(bean?instanceof?ApplicationContextAware)?{
??????((ApplicationContextAware)?bean).setApplicationContext(this.applicationContext);
???}
}
看到這里,答案就有了。ApplicationEventPublisherAware所獲得的ApplicationEventPublisher實(shí)例就是當(dāng)前的ApplicationContext。
簡述Spring Boot事件
Springboot事件
SpringBoot事件繼承ApplicationEvent,也是SpringApplicationEvent的子類
SpringBoot事件源是SpringApplication,內(nèi)部事件根據(jù)EventPublishingRunListener的生命周期回調(diào)方法依次發(fā)布。
ApplicationStartingEvent 1.5出現(xiàn) ApplicationEnvironmentPreparedEvent ApplicationPreparedEvent ApplicationStartedEvent ApplicationReadyEvent, spring應(yīng)用上下文之后發(fā)布 ApplicationFailedEvent, spring應(yīng)用上下文之后發(fā)布
Spring Boot事件監(jiān)聽手段
SpringApplication關(guān)聯(lián)的SpringApplication關(guān)聯(lián)ApplicationListener
class-path下,META-INF/spring.factories資源中的ApplicationListener對象集合
SpringApplication#addListeners(...)或SpringApplicationBuilder#listeners(...)顯示裝配
Spring Boot的廣播器
SimpleApplicationEventMulticaster,是特定的,2.0以后不與spring framework共用。
往期推薦
歡迎加入我的知識星球,聊技術(shù)、說職場、侃社會(huì)。



