Spring的事件發(fā)布與監(jiān)聽(tīng)方式案例講解
事件
主要代碼在org.springframework.context,org.springframework.context.event包中
事件發(fā)布與監(jiān)聽(tīng)主要包含以下角色:
- 事件:
ApplicationEvent - 事件監(jiān)聽(tīng)器:
ApplicationListenerSmartApplicationListenerGenericApplicationListener - 事件發(fā)布器:
ApplicationEventPublisher - 事件廣播器:
ApplicationEventMulticaster
引入ApplicationListener有兩種方式:
- spring spi
- 手動(dòng)注入bean
手動(dòng)注入bean有兩種方式:
- 類(lèi)上注解
@Component等注解+實(shí)現(xiàn)ApplicationListener接口 - 類(lèi)上注解
@Component等注解+方法上注解@EventListener
案例如下:
// bean注入方式一,實(shí)現(xiàn)ApplicationListener+@Component注入bean
@Component
public class HelloEventListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
}
}
// bean注入方式二,@EventListener+@Component
@Component
public class Test {
@EventListener
public void listen(Object obj){
System.out.println("listening");
}
@EventListener(classes={ApplicationEvent.class},condition="springEL")
public void listen(ApplicationEvent event){
System.out.println("listening");
}
}
關(guān)于@EventListener注解方法注入是通過(guò)EventListenerMethodProcessor的一個(gè)SmartInitializingSingleton,同時(shí)該類(lèi)也是一個(gè)BeanFactoryPostProcessor,但掃描@EventListener方法和注入邏輯不在該接口的postProcess方法中,而是SmartInitializingSingleton接口的afterSingletonsInstantiated方法。
關(guān)于SmartInitializingSingleton的接口作用注釋如下:
Callback interface triggered at the end of the singleton pre-instantiation phase during BeanFactory bootstrap. This interface can be implemented by singleton beans in order to perform some initialization after the regular singleton instantiation algorithm, avoiding side effects with accidental early initialization (e.g. from ListableBeanFactory.getBeansOfType calls). In that sense, it is an alternative to InitializingBean which gets triggered right at the end of a bean’s local construction phase.
看到其作用和 InitializingBean 類(lèi)似,用于構(gòu)造函數(shù)后的初始化操作,不過(guò)該接口是所有bean被創(chuàng)建之后被調(diào)用。在所有 bean的構(gòu)造方法、初始化(@PostConstruct、InitializingBean)、BeanPostProcessor都執(zhí)行完畢后再執(zhí)行該接口方法,注意是所有bean都執(zhí)行完這些方法。
Invoked right at the end of the singleton pre-instantiation phase, with a guarantee that all regular singleton beans have been created already.
public class EventListenerMethodProcessor
implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {
// 負(fù)責(zé)設(shè)置EventListenerFactory
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 回調(diào)beanFactory賦值
this.beanFactory = beanFactory;
// 拿到所有的EventListenerFactory
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
// 設(shè)置eventListenerFactories
this.eventListenerFactories = factories;
}
@Override
public void afterSingletonsInstantiated() {
...
processBean(beanName, type);
...
}
private void processBean(final String beanName, final Class<?> targetType) {
if (
// 不包含@EventListener的類(lèi)的備忘錄是否有該類(lèi)型
!this.nonAnnotatedClasses.contains(targetType) &&
// 該類(lèi)型的type, method or field 是否能被注解@EventListener
AnnotationUtils.isCandidateClass(targetType, EventListener.class) &&
// 不能是org.springframework開(kāi)頭的類(lèi),或者被注解了@Component,注意是或者
!isSpringContainerClass(targetType)
) {
// 提取所有的方法
Map<Method, EventListener> annotatedMethods = null;
try {
annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
}
...
if (CollectionUtils.isEmpty(annotatedMethods)) {
// 備忘錄,加入已掃描的沒(méi)有注解@EventListener的類(lèi)
this.nonAnnotatedClasses.add(targetType);
...
}
else {
// Non-empty set of methods
ConfigurableApplicationContext context = this.applicationContext;
Assert.state(context != null, "No ApplicationContext set");
List<EventListenerFactory> 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));
// 生成ApplicationListener
ApplicationListener<?> applicationListener =
factory.createApplicationListener(beanName, targetType, methodToUse);
if (applicationListener instanceof ApplicationListenerMethodAdapter) {
((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
}
context.addApplicationListener(applicationListener);
break;
}
...ApplicationListener監(jiān)聽(tīng)到事件后的執(zhí)行是同步過(guò)程,如果需要異步,可搭配@Async+@EventListener
事務(wù)消息監(jiān)聽(tīng)器
spring-tx包下提供TransactionalApplicationListener接口和@TransactionalEventListener注解。
TransactionalApplicationListener接口:An ApplicationListener that is invoked according to a TransactionPhase. NOTE: Transactional event listeners only work with thread-bound transactions managed by a PlatformTransactionManager.
到此這篇關(guān)于Spring的事件發(fā)布與監(jiān)聽(tīng)方式案例講解的文章就介紹到這了,更多相關(guān)Spring事件發(fā)布與監(jiān)聽(tīng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 詳解SpringBoot實(shí)現(xiàn)ApplicationEvent事件的監(jiān)聽(tīng)與發(fā)布
- spring event 事件異步處理方式(發(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ī)制
- 詳解SpringBoot 發(fā)布ApplicationEventPublisher和監(jiān)聽(tīng)ApplicationEvent事件
相關(guān)文章
SpringBoot應(yīng)用啟動(dòng)內(nèi)置Tomcat的過(guò)程源碼分析
這篇文章主要介紹了SpringBoot應(yīng)用啟動(dòng)內(nèi)置Tomcat的過(guò)程分析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
Mybatis-Plus3.x的創(chuàng)建步驟及使用教程
MyBatis-Plus是一個(gè)?MyBatis?的增強(qiáng)工具,在?MyBatis?的基礎(chǔ)上只做增強(qiáng)不做改變,為?簡(jiǎn)化開(kāi)發(fā)、提高效率而生,這篇文章主要介紹了Mybatis-Plus3.x的使用,需要的朋友可以參考下2023-10-10
SpringSecurity6自定義JSON登錄的實(shí)現(xiàn)
目前最新版的Spring Boot已經(jīng)到了3.0.5了,隨之而來(lái)Spring Security 目前的版本也到了6.0.2了,Spring Security寫(xiě)法的變化特別多,本文就來(lái)介紹下,感興趣的可以了解一下2023-12-12
關(guān)于文件上傳MultipartBody的使用方法
這篇文章主要介紹了關(guān)于文件上傳MultipartBody的使用方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Java權(quán)重隨機(jī)的實(shí)現(xiàn)方法
這篇文章主要介紹了Java權(quán)重隨機(jī)的實(shí)現(xiàn)方法,實(shí)例分析了權(quán)重隨機(jī)算法的原理與完整實(shí)現(xiàn)方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01
Spring?Boot如何接入Security權(quán)限認(rèn)證服務(wù)

