Spring Event
使用Spring Event,可以轻松实现业务解耦。只需要将事件发布出去,注册的监听器可以针对这个事件执行对应的业务逻辑。适用于同一个应用内的事件监听。比如审核通过,需要初始化下一个流程相关业务逻辑、给用户发送通知消息、写入变更历史表、发送消息到消息队列等。
定义事件
继承ApplicationEvent,将需要传递的事件信息包装为业务事件类,如下所示。
public class AuditEvent extends ApplicationEvent {
private Object source;
private int auditStatus; // 审核状态
private long auditId; // 审核ID
public AuditEvent(Object source, int auditStatus, long auditId) {
super(source);
this.auditStatus = auditStatus;
this.auditId = auditId;
}
// getter
}
事件发布
注入ApplicationEventPublisher,通过publishEvent方法即可发布事件。ApplicationEventPublisher的一般实现是AbstractApplicationContext,即Spring容器本身就是可以发送Spring事件。
@Service
public class AuditService {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
public void audit(int auditStatus, long auditId) {
// 修改数据库审核状态
auditMapper.updateStatusById(auditStatus, auditId);
// 发送审核事件
applicationEventPublisher.publishEvent(new AuditEvent(this, auditStatus, auditId));
}
}
事件监听
实现对应事件的监听器,需要继承ApplicationListener,并实现onApplicationEvent方法。通过泛型指定需要监听的事件类。
@Component
public class AuditEventListener implements ApplicationListener<AuditEvent> {
@Override
public void onApplicationEvent(AuditEvent auditEvent) {
// 事件处理
}
}
@EventListener
也可以使用@EventListener注解方法,将其包装为事件处理器。它适用于:1. 不想为每个事件处理都创建一个ApplicationListener实现类;2. 希望支持更复杂的事件条件过滤。@EventListener的classes属性可以过滤事件类型,而condition属性可以根据事件对象是否满足条件表达式来过滤事件。
@Component
public class EventProcessor {
@EventListener(classes={CustomEvent.class}, condition="#event.status==1")
public void process(CustomEvent event) {
// 事件处理
}
}
异步处理
默认情况下,ApplicationListener处理事件是同步执行的。如果要处理耗时操作,希望异步执行,有三种方案:
- 自定义ApplicationEventMulticaster
后面可以看到,Spring容器会优先使用beanName为applicationEventMulticater
的bean作为事件转发处理器,如果不存在则默认使用SimpleApplicationEventMulticaster作为事件转发处理器,它默认是同步执行的。但它支持设置Executor,那么我们可以将自定义的线程池处理器作为Executor,以此来支持异步执行。
@Configuration
public class Config {
@Bean
public SimpleApplicationEventMulticaster applicationEventMulticater() {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster();
multicaster.setTaskExecutor(Executors.newFixedThreadPool(1)); // 自定义线程池
return multicaster;
}
}
不过这样设置之后,所有Listener都是异步执行。对于需要同时支持异步和同步执行的应用,考虑下面的方案。
- 手动提交线程池异步执行
适用于简单的场景。但这样对代码的侵入性比较高,
private Executor executor = Executors.newFixedThreadPool(1);
public void onApplicationEvent(CustomEvent event) {
executor.execute(() -> process(event));
}
- 使用@Async 注解
对于@EventListener注解的方法处理器,可以使用@Async注解,使得方法调用变为异步调用。(需要在启动类Application上使用@EnableAsync注解,引入对@Async的支持。)
感知事务 @TransactionalEventListener
业务可能并不希望事件在发布的时候就立马执行,而是与事务的某个阶段进行绑定。比如在事务提交之后(出错的概率比较低),发送短信通知用户。@TransactionEventListener允许事件处理方法感知事务。它的phase属性,表示希望在事务的哪个阶段执行事件处理。
如下所示,当在事务环境下(@Transactional 注解),发送事件时,如果使用TransactionalEventListener监听事件,那么默认情况下会延迟到事务已提交之后才开始执行。这样避免在后续操作出错、导致事务回滚的情况下,事件已经被处理,无法撤回。
@Service
public class AuditService {
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
// 事务环境
@Transactional
public void audit(int auditStatus, long auditId) {
// 修改数据库审核状态
auditMapper.updateStatusById(auditStatus, auditId);
// 发送审核事件
applicationEventPublisher.publishEvent(new AuditEvent(this, auditStatus, auditId));
// 做一些其他操作
}
}
@Component
public class EventProcessor {
@TransactionalEventListener(phase=TransactionPhase.AFTER_COMMIT)
public void whenCommit(CustomEvent event) {
// 只在事务已提交后,触发事件
}
@TransactionalEventListener(phase=TransactionPhase.AFTER_ROLLBACK)
public void whenRollback(CustomEvent event) {
// 只在事务回滚的情况下,触发事件
}
}
源码分析:事件发布与转发
ApplicationEventPublisher
Spring容器(父类AbstractApplicationContext)把自身作为ApplicationEventPublisher类的实现注册到容器中
// AbstractApplicationContext#prepareBeanFactory
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
AbstractApplicationContext作为ApplicationEventPublisher,实现了publishEvent方法,将其转发给内部实现:
- 包装非ApplicationEvent对象为PayloadApplicationEvent
- 在Listener初始化之前保存早期发布的事件
- 在初始化之后直接给交给applicationEventMulticaster发布事件
- 同时将事件发布给父容器(如果有,且是AbstractApplicationContext实现)
// AbstractApplicationContext
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
@Override
public void publishEvent(Object event) {
publishEvent(event, null);
}
// 具体实现
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
// 包装ApplicationEvent
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// 考虑到部分事件在Listener注册之前就发布了,因此先保存起来
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// 同时给父容器发布事件
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
也就是事件转发依赖ApplicationEventMulticaster对象。容器初始化过程中会先完成ApplicationEventMulticaster对象的初始化,再注册Listener。
// AbstractApplicationContext
public void refresh() {
prepareRefresh();
...
initApplicationEventMulticaster();
onRefresh();
registerListeners(); // 注册监听器
...
}
如果容器中已经注册有名为applicationEventMulticaster
的Bean,则使用它(我们可以通过这种方式注册自定义的ApplicationEventMulticaster,比如添加线程处理器),否则默认使用SimpleApplicationEventMulticaster作为转发器。
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
}
将容器注册的Listener和Listener Bean,注册到applicationEventMulticaster。同时开始转发早期收集的事件。
protected void registerListeners() {
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}
// 从容器中获取实现ApplicationListener的Bean
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// 初始化之前收集的事件,这时候开始转发
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (earlyEventsToProcess != null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}
关于earlyApplicationEvents
AbstractApplicationContext的refresh()方法确定了容器初始化的流程,在prepareRefresh()中将earlyApplicationEvents初始化为空列表,再此之后初始化过程中发送的事件,都将保存在earlyApplicationEvents中。而后续先初始化applicationEventMulticaster,再注册完监听器,此时会将earlyApplicationEvents中所有事件发送给监听器,然后置为null,至此earlyApplicationEvents的任务就已经完成了。
SimpleApplicationEventMulticaster
SimpleApplicationEventMulticaster
继承自AbstractApplicationEventMulticaster
,后者实现了Listener和Listener Bean注册和移除、查找,前者在此基础上,实现了事件转发的功能。在multicastEvent方法中,遍历所有支持该事件类型的ApplicationListener,调用其onApplicationEvent方法。SimpleApplicationEventMulticaster
允许用户设置Executor,使用Executor执行事件处理程序。
// SimpleApplicationEventMulticaster
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
@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 {
// 执行 listener.onApplicationEvent(event);
invokeListener(listener, event);
}
}
}
AbstractApplicationEventMulticaster
的 defaultRetriever
(ListenerRetriever
类型)负责维护两个列表applicationListeners 和 applicationListenerBeans。Listener和Listener Bean的注册和移除都是对这两个列表的新增和删除。(为什么需要Listener Bean?支持1. 非singleton bean;2. FactoryBean)
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
this.defaultRetriever.applicationListeners.remove(listener);
this.retrieverCache.clear();
}
}
每次事件转发需要查询支持该事件类型的ApplicationListener:从defaultRetriever
维护的applicationListeners和applicationListenerBeans找到适用类型的ApplicationListener对象。最后按照Order优先级排序,并返回。
// 对于listenerBean来说,需要从容器中获取对应的Bean对象
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
allListeners.add(listener);
}
}
为了避免每次查询遍历一遍,使用retrieverCache作为缓存,这样对于相同的事件类型,可以直接返回对应的ApplicationListener列表。这也是为什么每次Listener和ListenerBean新增或移除,都要清空retrieverCache。
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 直接查询缓存
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)))) {
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// 不能安全使用缓存
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
源码分析:@EventListener
EventListenerMethodProcessor
AnnotationConfigUtils给容器提供了一些默认的注解处理器。包括EventListenerMethodProcessor方法注解处理器和默认的EventListenerFactory实现。
// AnnotationConfigUtils#registerAnnotationConfigProcessors
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));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
EventListenerMethodProcessor做了以下几件事:
- 从Bean容器中获取所有EventListenerFactory接口的实现(order排序)
- 在容器初始化单例对象结束后,遍历所有容器中bean的类,通过反射解析出该类中@EventListener注解的方法
- 将这些方法通过适合的EventListenerFactory调用
createApplicationListener
包装成ApplicationListener对象,并注册到ApplicationContext
// 1. 从Bean容器中获取所有EventListenerFactory接口的实现
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
List<EventListenerFactory> factories = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(factories);
this.eventListenerFactories = factories;
}
// 2. 在容器初始化单例对象结束后,遍历所有容器中bean的类
@Override
public void afterSingletonsInstantiated() {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
Class<?> type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
if (type != null) {
processBean(beanName, type);
}
}
}
private void processBean(final String beanName, final Class<?> targetType) {
if (!this.nonAnnotatedClasses.contains(targetType)) {
// 2.1 通过反射解析出该类中@EventListener注解的方法
Map<Method, EventListener> annotatedMethods = MethodIntrospector.selectMethods(targetType,
(MethodIntrospector.MetadataLookup<EventListener>) method ->
AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
if (CollectionUtils.isEmpty(annotatedMethods)) {
this.nonAnnotatedClasses.add(targetType);
}
else {
ConfigurableApplicationContext context = this.applicationContext;
List<EventListenerFactory> factories = this.eventListenerFactories;
for (Method method : annotatedMethods.keySet()) {
for (EventListenerFactory factory : factories) {
// 3. 将这些方法通过适合的EventListenerFactory调用createApplicationListener
// 包装成ApplicationListener对象
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);
}
// 3.1 注册到ApplicationContext
context.addApplicationListener(applicationListener);
break;
}
}
}
}
}
}
EventListenerFactory
DefaultEventListenerFactory是默认的EventListenerFactory实现,支持所有方法。最后将方法包装为ApplicationListenerMethodAdapter对象。
public class DefaultEventListenerFactory implements EventListenerFactory, Ordered {
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
}
@Override
public boolean supportsMethod(Method method) {
return true;
}
@Override
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
return new ApplicationListenerMethodAdapter(beanName, type, method);
}
}
ApplicationListenerMethodAdatper
ApplicationListenerMethodAdapter使用了适配器的设计模式
- 从方法的@EventListener注解(或方法参数)中获取需要监听的事件类型,以及条件表达式,从方法的@Order注解中获取优先级信息。
supportsEventType
方法提供事件类型判断onApplicationEvent
方法收到事件对象时:- 通过方法支持的参数(是否无参)以及事件对象是否为
PayloadApplicationEvent
类型解析出方法调用需要的参数信息 - 根据注解的条件表达式,判断是否可以执行方法调用
- 执行方法调用
- 将方法调用的结果作为事件对象发布出去
- 通过方法支持的参数(是否无参)以及事件对象是否为
public void processEvent(ApplicationEvent event) {
// 通过事件对象解析方法参数
Object[] args = resolveArguments(event);
// 条件表达式判断
if (shouldHandle(event, args)) {
// 反射执行
Object result = doInvoke(args);
if (result != null) {
// 将结果作为事件发布
handleResult(result);
}
}
}
源码分析:@TransactionalEventListener
TransactionalEventListenerFactory
TransactionalEventListenerFactory优先将被@TransactionalEventListener注解的方法包装为感知事务的ApplicationListener。
public class TransactionalEventListenerFactory implements EventListenerFactory, Ordered {
private int order = 50; // 优先级比DefaultEventListenerFactory高
@Override
public int getOrder() {
return this.order;
}
@Override
public boolean supportsMethod(Method method) {
return AnnotatedElementUtils.hasAnnotation(method, TransactionalEventListener.class);
}
@Override
public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
return new ApplicationListenerMethodTransactionalAdapter(beanName, type, method);
}
}
ApplicationListenerMethodTransactionalAdapter
继承自ApplicationListenerMethodAdapter,提供了基础的事件类型解析和方法调用逻辑。但它依赖当前环境中是否有事务,通过注册事务同步器,在事务状态转移的时候执行相应的回调任务。这样能够将事件处理和某些事务状态进行绑定执行。
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);
this.annotation = ann;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
// 事务处于开启状态
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 注册事务同步器,在事务状态转移的时候执行相应的回调任务
TransactionSynchronization transactionSynchronization = createTransactionSynchronization(event);
TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
}
else if (this.annotation.fallbackExecution()) {
// fallbackExecution为true,表明没有事务的时候也执行
processEvent(event);
}
else {
// fallbackExecution为false,没有事务,不处理
}
}
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;
}
@Override
public int getOrder() {
return this.listener.getOrder();
}
@Override
public void beforeCommit(boolean readOnly) {
if (this.phase == TransactionPhase.BEFORE_COMMIT) {
processEvent();
}
}
@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);
}
}
}
总结
Spring Event使用ApplicationEventPublisher发布事件,通过实现ApplicationListener监听事件。这种模式可以解耦复杂的业务依赖。用@EventListener或@TransactionalEventListener注解处理函数,可以提供更复杂的条件过滤,或者事务状态感知,支持业务实现更复杂的事件处理。
从源码实现方面,AbstractApplicationContext在refresh过程中初始化ApplicationEventMulticaster(SimpleApplicationEventMulticaster)和ApplicationListener,并向ApplicationEventMulticaster注册监听器。这样在发布事件后,ApplicationEventMulticaster能够找到类型匹配的ApplicationListener,并执行调用。
对于@EventListener或@TransactionalEventListener,则依赖方法处理器EventListenerMethodProcessor遍历所有bean并找出被注解的方法,用对应的EventListenerFactory(DefaultEventListenerFactory或者TransactionalEventListenerFactory)将该方法包装为ApplicationListener。对于@TransactionalEventListener来说,需要额外通过事务同步器感知事务状态变动。