spring中的事件监听机制
一、前言
事件监听机制也是设计模式中观察者模式的一种实现。在spring中主要有实现ApplicationListener 接口和@EventListener 注解两种方式实现。
实现事件监听机制需要以下三个角色:
1、事件(event)可以封装和传递监听器中要处理的参数,如对象或字符串,并作为监听器中监听的目标。
2、监听器(listener)具体根据事件发生的业务处理模块,这里可以接收处理事件中封装的对象或字符串。
3、事件发布者(publisher)事件发生的触发者。
二、ApplicationListener 接口
ApplicationListener 接口的定义如下:
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
它是一个泛型接口,泛型的类型必须是 ApplicationEvent 及其子类,只要实现了这个接口,那么当容器有相应的事件触发时,就能触发 onApplicationEvent 方法。ApplicationEvent 类的子类有很多,Spring 框架自带的如下几个。
使用方法很简单,就是实现一个 ApplicationListener 接口,并且将加入到容器中就行。
@Component public class MyApplicationListener implements ApplicationListener<ApplicationStartedEvent> { // @Override // public void onApplicationEvent(ApplicationEvent event) { // System.out.println("事件触发:"+event.getClass().getName()); // } @Override public void onApplicationEvent(ApplicationStartedEvent event) { System.out.println("事件触发:"+event.getClass().getName()); } }
可以看到控制台输出:这样就触发了spring默认的一些事件。
事件触发:org.springframework.boot.context.event.ApplicationStartedEvent
事件触发:org.springframework.boot.context.event.ApplicationReadyEvent
自定义事件监听
定义事件
首先,我们需要定义一个时间(MyTestEvent),需要继承Spring的ApplicationEvent
public class MyTestEvent extends ApplicationEvent { private static final long serialVersionUID = 1L; private String msg ; public MyTestEvent(Object source,String msg) { super(source); this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
定义监听器
需要定义一下监听器,自己定义的监听器需要实现ApplicationListener,同时泛型参数要加上自己要监听的事件Class名,在重写的方法onApplicationEvent中,添加自己的业务处理:
@Component public class MyNoAnnotationListener implements ApplicationListener<MyTestEvent> { @Override public void onApplicationEvent(MyTestEvent event) { System.out.println("非注解监听器:" + event.getMsg()); } }
事件发布
有了事件,有了事件监听者,那么什么时候触发这个事件呢?每次想让监听器收到事件通知的时候,就可以调用一下事件发布的操作。首先在类里自动注入了ApplicationEventPublisher,这个也就是我们的ApplicationContext,它实现了这个接口。
@RestController @RequestMapping("testEventController") public class MyTestEventController { @Autowired private ApplicationEventPublisher applicationEventPublisher; @RequestMapping(value = "/testPublishEvent1" ) public void testPublishEvent(){ applicationEventPublisher.publishEvent(new MyTestEvent(this, "我来了")); } }
输出结果如下图所示:
非注解监听器:我来了
三、@EventListener 注解
从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface EventListener { @AliasFor("classes") Class<?>[] value() default {}; //监听的类 @AliasFor("value") Class<?>[] classes() default {}; String condition() default ""; }
简单使用
除了通过实现接口,还可以使用@EventListener 注解,实现对任意的方法都能监听事件。
在任意方法上标注@EventListener 注解,指定 classes,即需要处理的事件类型,一般就是 ApplicationEven 及其子类,可以设置多项。
@Compoment public class CustomListener { @EventListener(classes = {SpringApplicationEvent.class}) public void listen(SpringApplicationEvent event) { System.out.println("注解事件触发:" + event.getClass().getName()); } }
启动项目
可以看到控制台和之前的输出是一样的:
注解事件触发:org.springframework.boot.context.event.ApplicationStartedEvent
注解事件触发:org.springframework.boot.context.event.ApplicationReadyEvent
使用注解的好处是不用每次都去实现ApplicationListener,可以在一个class中定义多个方法,用@EventListener来做方法级别的注解。
和上面类似,事件以及事件发布不需要改变,只要这样定义监听器即可。
此时,就可以有一个发布,两个监听器监听到发布的消息了,一个是注解方式,一个是非注解方式
结果:
注解监听器----1:我来了
非注解监听器:我来了
原理
@Component public class MyAnnotationListener { @EventListener public void listener1(MyTestEvent event) { System.out.println("注解监听器1:" + event.getMsg()); } }
其实上面添加@EventListener
注解的方法被包装成了ApplicationListener
对象,上面的类似于下面这种写法,这个应该比较好理解。
@Component public class MyAnnotationListener implements ApplicationListener<MyTestEvent> { @Override public void onApplicationEvent(MyTestEvent event) { System.out.println("注解监听器1:" + event.getMsg()); } }
那么Spring是什么时候做这件事的呢?
查看SpringBoot
的源码,找到下面的代码,因为我是Tomcat环境,这里创建的ApplicationContext
是org.springframework.bootweb.servlet.context.AnnotationConfigServletWebServerApplicationContext
protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
他的构造方法如下:
public AnnotationConfigServletWebServerApplicationContext() { this.reader = new AnnotatedBeanDefinitionReader(this); this.scanner = new ClassPathBeanDefinitionScanner(this); }
进到AnnotatedBeanDefinitionReader
里面
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); Assert.notNull(environment, "Environment must not be null"); this.registry = registry; this.conditionEvaluator = new ConditionEvaluator(registry, environment, null); AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); }
再进到AnnotationConfigUtils
的方法里面,省略了一部分代码,可以看到他注册了一个EventListenerMethodProcessor
类到工厂了。这是一个BeanFactory
的后置处理器。
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry); ...... ..... ...... if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class); def.setSource(source); beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME)); } ...... ...... return beanDefs; }
查看这个BeanFactory
的后置处理器EventListenerMethodProcessor
,下面方法,他会遍历所有bean,找到其中带有@EventListener
的方法,将它包装成ApplicationListenerMethodAdapter
,注册到工厂里,这样就成功注册到Spring的监听系统里了。
@Override public void afterSingletonsInstantiated() { ConfigurableListableBeanFactory beanFactory = this.beanFactory; Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set"); String[] beanNames = beanFactory.getBeanNamesForType(Object.class); for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class<?> type = null; try { type = AutoProxyUtils.determineTargetClass(beanFactory, beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } if (type != null) { if (ScopedObject.class.isAssignableFrom(type)) { try { Class<?> targetClass = AutoProxyUtils.determineTargetClass( beanFactory, ScopedProxyUtils.getTargetBeanName(beanName)); if (targetClass != null) { type = targetClass; } } catch (Throwable ex) { // An invalid scoped proxy arrangement - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex); } } } try { processBean(beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex); } } } } } private void processBean(final String beanName, final Class<?> targetType) { if (!this.nonAnnotatedClasses.contains(targetType) && !targetType.getName().startsWith("java") && !isSpringContainerClass(targetType)) { Map<Method, EventListener> annotatedMethods = null; try { annotatedMethods = MethodIntrospector.selectMethods(targetType, (MethodIntrospector.MetadataLookup<EventListener>) 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<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 = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } context.addApplicationListener(applicationListener); break; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName + "': " + annotatedMethods); } } } }
由方法生成Listener
的逻辑由EventListenerFactory
完成的,这又分为两种,一种是普通的@EventLintener
另一种是@TransactionalEventListener
,是由两个工厂处理的。
上面介绍了@EventListener
的原理,其实上面方法里还有一个@TransactionalEventListener
注解,其实原理是一模一样的,只是这个监听者可以选择在事务完成后才会被执行,事务执行失败就不会被执行。
这两个注解的逻辑是一模一样的,并且@TransactionalEventListener
本身就被标记有@EventListener
,
只是最后生成监听器时所用的工厂不一样而已。
总结:
- 同样的事件能有多个监听器 -- 经过测试是可以的
- 事件监听操作和发布事件的操作是同步的吗? -- 是的,所以如果有事务,监听操作也在事务内。如果需要改为异步也可以手动使用多线程或者借用异步注解实现。
- EventListener这个注解其实可以接受参数来表示事件源的,有两个参数classes和condition,顾明思议前者是表示哪一个事件类,后者是当满足什么条件是会调用该方法,但其实都可以不用用到,直接在方法上写参数xxEvent就行
摘自:https://blog.csdn.net/m0_49558851/article/details/118903432
定义event事件模型
首先定义一个event事件模型。ComplaintDTO为事件发布者传送给事件监听者的一些信息,入投诉的订单信息、客户信息等。可根据自身需要进行调整,调整之后需要变动相应的get/set方法和构造方法。
import org.springframework.context.ApplicationEvent; public class ComplaintEvent extends ApplicationEvent { private ComplaintDTO complaintDTO; public ComplaintEvent(Object source,ComplaintDTO complaintDTO) { super(source); this.complaintDTO = complaintDTO; } public ComplaintDTO getComplaintDTO() { return complaintDTO; } public void setComplaintDTO(ComplaintDTO complaintDTO) { this.complaintDTO = complaintDTO; } }
发布事件
@Autowired private ApplicationEventPublisher applicationEventPublisher; @Override public ComplaintVO createComplaint(ComplaintDTO complaintDTO) { //TODO 你的业务代码 //发负一屏消息和短信 try{ ComplaintEvent complaintEvent = new ComplaintEvent(this,complaintDTO); applicationEventPublisher.publishEvent(complaintEvent); }catch (Exception e){ log.info("投诉发短信或负一屏消息失败:[{}]",e.getMessage()); } vo = Transferor.entity(po, ComplaintVO.class); return vo; }
事件监听者
事件的监听者实现ApplicationListener接口,重写onApplicationEvent方法实现事件处理
这里需要注意的是ApplicationEvent默认并不是异步的,如果需要异步需要我们在方法上加上@Async注解,并在启动类添加@EnableAsync开启异步
@Log4j2 @Component public class ComplaintEventListener implements ApplicationListener<ComplaintEvent> { @Async @Override public void onApplicationEvent(ComplaintEvent event) { log.info("订单投诉发短信与负一屏消息:[{}]", JSON.toJSONString(event)); //发短信 try { sendSmsMsg(event); }catch (Exception e){ log.info("订单投诉发短信失败:[{}]",e.getMessage()); } //发负一屏消息 try { sendHwPubMsg(event); }catch (Exception e){ log.info("订单投诉发负一屏消息失败:[{}]",e.getMessage()); } } }
从Spring 4.2以后,事件处理不用实现ApplicationListener 的 onApplicationEvent方法了,使用注解@EventListener可以自动关联相关的ApplicationListener。
所以上面的代码其实可以改成成下面的样子
@Log4j2 @Component public class ComplaintEventListener{ @Async @EventListener public void sendMsg(ComplaintEvent event) { log.info("订单投诉发短信与负一屏消息:[{}]", JSON.toJSONString(event)); //发短信 try { sendSmsMsg(event); }catch (Exception e){ log.info("订单投诉发短信失败:[{}]",e.getMessage()); } //发负一屏消息 try { sendHwPubMsg(event); }catch (Exception e){ log.info("订单投诉发负一屏消息失败:[{}]",e.getMessage()); } } }
摘自:https://fangshixiang.blog.csdn.net/article/details/91897175
Spring事务监听机制---使用@TransactionalEventListener处理数据库事务提交成功后再执行操作
@TransactionalEventListener
首先不得不说,从命名中就可以直接看出,它就是个EventListener
在Spring4.2+,有一种叫做@TransactionEventListener的方式,能够 控制 在事务的时候Event事件的处理方式。
我们知道,Spring的事件监听机制(发布订阅模型)实际上并不是异步的(默认情况下),而是同步的来将代码进行解耦。而@TransactionEventListener仍是通过这种方式,只不过加入了回调的方式来解决,这样就能够在事务进行Commited,Rollback…等的时候才会去进行Event的处理,达到事务同步的目的
Demo演示
@Slf4j @Service public class HelloServiceImpl implements HelloService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private ApplicationEventPublisher applicationEventPublisher; @Transactional @Override public Object hello(Integer id) { // 向数据库插入一条记录 String sql = "insert into user (id,name,age) values (" + id + ",'fsx',21)"; jdbcTemplate.update(sql); // 发布一个自定义的事件~~~ applicationEventPublisher.publishEvent(new MyAfterTransactionEvent("我是和事务相关的事件,请事务提交后执行我~~~", id)); return "service hello"; } @Slf4j @Component private static class MyTransactionListener { @Autowired private JdbcTemplate jdbcTemplate; @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) private void onHelloEvent(HelloServiceImpl.MyAfterTransactionEvent event) { Object source = event.getSource(); Integer id = event.getId(); String query = "select count(1) from user where id = " + id; Integer count = jdbcTemplate.queryForObject(query, Integer.class); // 可以看到 这里的count是1 它肯定是在上面事务提交之后才会执行的 log.info(source + ":" + count.toString()); //我是和事务相关的事件,请事务提交后执行我~~~:1 } } // 定一个事件,继承自ApplicationEvent private static class MyAfterTransactionEvent extends ApplicationEvent { private Integer id; public MyAfterTransactionEvent(Object source, Integer id) { super(source); this.id = id; } public Integer getId() { return id; } } }
首先确认,通过@TransactionalEventListener
注解的方式,是完全可以处理这种事务问题的。
接下来先看看这个注解本身,有哪些属性是我们可用、可控的:
// @since 4.2 显然,注解的方式提供得还是挺晚的,而API的方式第一个版本就已经提供了 // 另外最重要的是,它头上有一个注解:`@EventListener` so @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @EventListener //有类似于注解继承的效果 public @interface TransactionalEventListener { // 这个注解取值有:BEFORE_COMMIT、AFTER_COMMIT、AFTER_ROLLBACK、AFTER_COMPLETION // 各个值都代表什么意思表达什么功能,非常清晰~ // 需要注意的是:AFTER_COMMIT + AFTER_COMPLETION是可以同时生效的 // AFTER_ROLLBACK + AFTER_COMPLETION是可以同时生效的 TransactionPhase phase() default TransactionPhase.AFTER_COMMIT; // 若没有事务的时候,对应的event是否已经执行 默认值为false表示 没事务就不执行了 boolean fallbackExecution() default false; // 这里巧妙的用到了@AliasFor的能力,放到了@EventListener身上 // 注意:一般我建议都需要指定此值,否则默认可以处理所有类型的事件 范围太广了 @AliasFor(annotation = EventListener.class, attribute = "classes") Class<?>[] value() default {}; @AliasFor(annotation = EventListener.class, attribute = "classes") Class<?>[] classes() default {}; String condition() default ""; }
可以看到它实际上相当于在@EventListener的基础上扩展了两个属性,来对事务针对性的处理。
根据前面的Spring事件监听机制的理论知识得知:它的注册原理显然也在EventListenerMethodProcessor中,只不过它使用的是TransactionalEventListenerFactory最终来生成一个Adapter适配器:
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered { private int order = 50; // 执行时机还是比较早的~~~(默认的工厂是最低优先级) // 显然这个工厂只会生成标注有此注解的handler~~~ @Override public boolean supportsMethod(Method method) { return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class); } // 这里使用的是ApplicationListenerMethodTransactionalAdapter,而非ApplicationListenerMethodAdapter // 虽然ApplicationListenerMethodTransactionalAdapter是它的子类 @Override public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) { return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method); } }
通过这个工厂,会把每个标注有@TransactionalEventListener
注解的方法最终都包装成一个ApplicationListenerMethodTransactionalAdapter
,它是一个ApplicationListener
,最终注册进事件发射器的容器里面。
ApplicationListenerMethodTransactionalAdapter
它是包装@TransactionalEventListener
的适配器,继承自ApplicationListenerMethodAdapter
~
// @since 4.2 class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter { private final TransactionalEventListener annotation; // 构造函数 public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) { // 这一步的初始化交给父类,做了很多事情 强烈建议看看上面推荐的事件/监听的博文 super(beanName, targetClass, method); // 自己个性化的:和事务相关 TransactionalEventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class); if (ann == null) { throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method); } this.annotation = ann; } @Override public void onApplicationEvent(ApplicationEvent event) { // 若**存在事务**:毫无疑问 就注册一个同步器进去~~ if (TransactionSynchronizationManager.isSynchronizationActive()) { TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event); TransactionSynchronizationManager.registerSynchronization(transactionSynchronization); } // 若fallbackExecution=true,那就是表示即使没有事务 也会执行handler else if (this.annotation.fallbackExecution()) { if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) { logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase"); } processEvent(event); } else { // No transactional event execution at all // 若没有事务,输出一个debug信息,表示这个监听器没有执行~~~~ if (logger.isDebugEnabled()) { logger.debug("No transaction is active - skipping " + event); } } } // TransactionSynchronizationEventAdapter是一个内部类,它是一个TransactionSynchronization同步器 // 此类实现也比较简单,它的order由listener.getOrder();来决定 private TransactionSynchronization createTransactionSynchronization(ApplicationEvent event) { return new TransactionSynchronizationEventAdapter(this, event, this.annotation.phase()); } private static class TransactionSynchronizationEventAdapter extends TransactionSynchronizationAdapter { private final ApplicationListenerMethodAdapter listener; private final ApplicationEvent event; private final TransactionPhase phase; public TransactionSynchronizationEventAdapter(ApplicationListenerMethodAdapter listener, ApplicationEvent event, TransactionPhase phase) { this.listener = listener; this.event = event; this.phase = phase; } // 它的order又监听器本身来决定 @Override public int getOrder() { return this.listener.getOrder(); } // 最终都是委托给了listenner来真正的执行处理 来执行最终处理逻辑(也就是解析classes、condtion、执行方法体等等) @Override public void beforeCommit(boolean readOnly) { if (this.phase == TransactionPhase.BEFORE_COMMIT) { processEvent(); } } // 此处结合status和phase 判断是否应该执行~~~~ // 此处小技巧:我们发现TransactionPhase.AFTER_COMMIT也是放在了此处执行的,只是它结合了status进行判断而已~~~ @Override public void afterCompletion(int status) { if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) { processEvent(); } else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) { processEvent(); } else if (this.phase == TransactionPhase.AFTER_COMPLETION) { processEvent(); } } protected void processEvent() { this.listener.processEvent(this.event); } } }
从源码里可以看出,其实@TransactionalEventListener的底层实现原理还是事务同步器:TransactionSynchronization和TransactionSynchronizationManager。
以上,建立在小伙伴已经知晓了Spring事件/监听机制的基础上,回头看Spring事务的监听机制其实就非常非常的简单了(没有多少新东西)。
至于在平时业务编码中处理Spring的事务同步的时候选择哪种方式呢??我觉得两种方式都是ok的,看各位的喜好了(我个人偏爱注解方式,耦合度低很多并且还可以使用事件链,有时候非常好使)
需要提一句:
@TransactionalEventListener
同@EventListener
一样是存在一个加载时机问题的,若你对加载时机有严格要求和把控,建议使用API的方式而非注解方式,避免监听器未被执行而导致逻辑出错~
摘自:https://www.jianshu.com/p/96181bba0326
spring event demo - 异步模式
加上配置,注入一个simpleApplicationEventMulticaster。将这个multicaster的taskexecutor设置为自定义的线程池。
当publish event时,当前线程会到从线程池里来取线程,进行invoke listener,以及执行subscriber逻辑。
@Configuration public class EventConfig { @Bean(AbstractApplicationContext.APPLICATION_EVENT_MULTICASTER_BEAN_NAME) public SimpleApplicationEventMulticaster myEventMulticaster(){ SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(); simpleApplicationEventMulticaster.setTaskExecutor(taskExecutor()); return simpleApplicationEventMulticaster; } @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); executor.setMaxPoolSize(20); executor.setQueueCapacity(100); executor.setKeepAliveSeconds(300); executor.setThreadNamePrefix("thread-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
或者这样传入配置的线程池
@Bean public SimpleApplicationEventMulticaster applicationEventMulticaster(@Qualifier("defaultThreadPoolExecutor") ThreadPoolExecutor defaultThreadPoolExecutor) { SimpleApplicationEventMulticaster simpleApplicationEventMulticaster = new SimpleApplicationEventMulticaster(); simpleApplicationEventMulticaster.setTaskExecutor(defaultThreadPoolExecutor); return simpleApplicationEventMulticaster; }
output:
从output可以看出,主线程publish event,而subscriber内容由线程池中的线程执行。
Thread main: Publish Event
thread-1: Subscribed event - test
源码解析
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { /*setTaskExecutor Set the TaskExecutor to execute application listeners with. Default is a SyncTaskExecutor, executing the listeners synchronously in the calling thread. Consider specifying an asynchronous TaskExecutor here to not block the caller until all listeners have been executed. However, note that asynchronous execution will not participate in the caller's thread context (class loader, transaction association) unless the TaskExecutor explicitly supports this. */ public void setTaskExecutor(@Nullable Executor taskExecutor) { this.taskExecutor = taskExecutor; } }
Spring容器中的通知机制是如何实现的
初始化SimpleApplicationEventMulticaster并注入容器
Spring在初始化bean时,会进行ApplicationEventMulticaster的初始化。
会先检查是否有local的applicationEventMulticaster,如果有,那么就会创建local也就是自定义的applicationEventMulticaster,放入容器;如果没有,就会创建默认的SimpleApplicationEventMulticaster放入容器。
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if (beanFactory.containsLocalBean("applicationEventMulticaster")) { this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class); if (this.logger.isTraceEnabled()) { this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster); if (this.logger.isTraceEnabled()) { this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } } }
注册所有的监听器
接下来,spring容器会注册所有的监听器:
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { protected void registerListeners() { Iterator var1 = this.getApplicationListeners().iterator(); while(var1.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var1.next(); this.getApplicationEventMulticaster().addApplicationListener(listener); } String[] listenerBeanNames = this.getBeanNamesForType(ApplicationListener.class, true, false); String[] var7 = listenerBeanNames; int var3 = listenerBeanNames.length; for(int var4 = 0; var4 < var3; ++var4) { String listenerBeanName = var7[var4]; this.getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (!CollectionUtils.isEmpty(earlyEventsToProcess)) { Iterator var9 = earlyEventsToProcess.iterator(); while(var9.hasNext()) { ApplicationEvent earlyEvent = (ApplicationEvent)var9.next(); this.getApplicationEventMulticaster().multicastEvent(earlyEvent); } } } }
addApplicationListener会将listener和相应的事件类型记录下来:
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware { public void addApplicationListener(ApplicationListener<?> listener) { synchronized(this.defaultRetriever) { Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } } }
事件发生时,multicast event
-
调用multicaster的multicastEvent方法
上面已经提到,事件发生时,会调用AbstractApplicationContext的publishEvent方法,它会调用注入到容器里的multicaster执行multicastEvent。 -
根据事件类型,找到所有监听这类事件的listener
Iterator var5 = this.getApplicationListeners(event, type).iterator();
详细看下getApplicationListeners方法:
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = source != null ? source.getClass() : null; AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType); AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null; AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey); if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever(); existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever); if (existingRetriever != null) { newRetriever = null; } } if (existingRetriever != null) { Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } } return this.retrieveApplicationListeners(eventType, sourceType, newRetriever); }
- 对于每一个listener,invoke该listener
while(var5.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var5.next(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } }
参考文章:
https://blog.csdn.net/erbao_2014/article/details/68924231
https://www.huangchaoyu.com/2020/08/08/SpringBoot-%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6,EventListener%E6%B3%A8%E8%A7%A3%E5%8E%9F%E7%90%86
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库