前言
我们在业务开发中,强调低耦合编码,典型的比如业务逻辑处理后要进行短信、邮件等通知,对于这类非主要业务逻辑,就需要想办法解耦出去:
java
public void handler() {
....
// 业务逻辑
...
// 解耦逻辑 如消息、短息、邮件 等
....
}
解耦方式多种多样,常见的如观察者模式(事件监听),在特定的业务动作发生之后,将其包装成事件(event)发送出去,观察者们监听到对应的事件后,便可进行处理。
更重要的是,这种模式真正的做到了 开闭原则
,即 对扩展开放、对修改封闭
。比如说,当我们对该事件有新的处理逻辑时,只需要新增一个观察者,在新增的观察者中实现其逻辑即可。
可以看到,对原来的业务流程无修改,仅新增一个观察者即可解决。
回归正题
@TransactionalEventListener 是什么?
Spring 提供了事件监听机制(事件类型 ApplicationEvent
),通过 @EventListener 可以监听发送的事件消息并处理。
当然,正如其名,@TransactionalEventListener 也仍然是事件监听器,不同的是它与 Spring 的 事务
相关联。
业务逻辑处理:
java
@Transactional(rollbackFor = Exception.class)
public void handler() {
....
// 业务逻辑
...
// 解耦逻辑 如消息、短息、邮件 等
// push event
....
}
监听器:
java
@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void eventListenr(ContextRefreshedEvent contextRefreshedEvent) {
// do listener logic
}
如上,当事件消息已经从业务处理层投递出去后,业务逻辑发生了异常,导致事件回滚。如果是 @EventListener 则仍然会继续处理监听逻辑,很显然发生异常回滚之后不应该继续执行。
这就是 @TransactionalEventListener 可以 确保 Spring 事务提交之后再执行事件监听逻辑....
原理
@TransactionalEventListener 是 Spring 框架中的一个注解,用于在事务提交或回滚时处理事件。它结合了事务管理和事件驱动编程的优点,允许开发者在事务的不同阶段执行事件处理逻辑。
作用
@TransactionalEventListener 的主要作用是监听事务事件
,并在事务完成(提交或回滚)后执行相应的事件处理逻辑。它可以确保事件处理逻辑只在事务成功提交后执行,或者在事务回滚时执行。
值得注意的是,如果你的业务层并没有使用 Spring 事务,则 @TransactionalEventListener 监听不起作用,如何让其起作用?
指定注解参数 fallbackExecution=true
,即无事务的场景下也执行事件
工作机制
@TransactionalEventListener 依赖于 Spring 的事件发布机制
和事务管理机制
。它通过监听事务的生命周期事件(如提交或回滚),在事务完成后触发相应的事件处理方法。其工作原理如下:
- 事件发布:在事务中发布事件。
- 事件监听:@TransactionalEventListener 注解的方法会监听该事件。
- 事务完成后执行:根据配置,事件处理逻辑会在事务提交成功后或回滚时执行。
1. 注解定义:
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TransactionalEventListener {
TransactionPhase phase() default TransactionPhase.AFTER_COMMIT;
boolean fallbackExecution() default false;
String condition() default "";
}
- phase:指定事件处理的事务阶段。
- fallbackExecution:如果没有事务活动,是否仍然执行。
- condition:条件表达式,满足条件时才执行。
2. 事件发布
在事务中发布事件通常使用 ApplicationEventPublisher:
java
@Component
public class MyService {
@Autowired
private ApplicationEventPublisher eventPublisher;
@Transactional
public void performAction() {
...
// biz logic
...
// push event
eventPublisher.publishEvent(new MyEvent(this, "事件消息"));
}
}
3. 事件监听器的注册
Spring 在启动时会扫描所有的 @TransactionalEventListener 注解的方法,并将它们注册为事件监听器。这个过程由 EventListenerMethodProcessor 类负责。
4. 事务事件监听器的处理
TransactionalEventListener 的核心处理逻辑在 ApplicationListenerMethodTransactionalAdapter 类中。这个类实现了 ApplicationListener 接口,并在事务完成后调用相应的事件处理方法。
关键步骤:
- 事件拦截:当事件发布时,TransactionalApplicationListenerMethodAdapter 会拦截事件。
- 事务同步:它使用 TransactionSynchronizationManager 注册一个 TransactionSynchronization,以便在事务完成时执行。
- 事务阶段执行:根据 phase 属性,选择在事务提交、回滚或完成时执行事件处理方法。
5. 事务同步机制
Spring 的事务管理通过 TransactionSynchronizationManager 来管理事务同步。TransactionalApplicationListenerMethodAdapter 会在事务同步中注册一个回调,以便在事务完成时调用事件处理方法。
6. 源码呈现
java
class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerMethodAdapter {
private final TransactionalEventListener annotation;
public ApplicationListenerMethodTransactionalAdapter(String beanName, Class<?> targetClass, Method method) {
super(beanName, targetClass, method);
TransactionalEventListener ann = (TransactionalEventListener)AnnotatedElementUtils.findMergedAnnotation(method, TransactionalEventListener.class);
if (ann == null) {
throw new IllegalStateException("No TransactionalEventListener annotation found on method: " + method);
} else {
this.annotation = ann;
}
}
public void onApplicationEvent(ApplicationEvent event) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 监听事件发布,并注册至事务同步器中,当事务处理之后会进行回调
TransactionSynchronization transactionSynchronization = this.createTransactionSynchronization(event);
TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
} else if (this.annotation.fallbackExecution()) {
if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && this.logger.isWarnEnabled()) {
this.logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
}
this.processEvent(event);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("No transaction is active - skipping " + event);
}
}
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;
}
public int getOrder() {
return this.listener.getOrder();
}
public void beforeCommit(boolean readOnly) {
if (this.phase == TransactionPhase.BEFORE_COMMIT) {
this.processEvent();
}
}
// 监听事务的不同阶段,按指定的阶段触发 事件执行
public void afterCompletion(int status) {
if (this.phase == TransactionPhase.AFTER_COMMIT && status == 0) {
this.processEvent();
} else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == 1) {
this.processEvent();
} else if (this.phase == TransactionPhase.AFTER_COMPLETION) {
this.processEvent();
}
}
protected void processEvent() {
this.listener.processEvent(this.event);
}
}
}
核心工作流程小结
- 事件发布:在事务中发布事件。
- 事件拦截:ApplicationListenerMethodTransactionalAdapter 拦截事件,并检查事务状态。
- 注册同步:如果事务活动,注册一个事务同步对象。
- 事务阶段执行:在事务的指定阶段(如提交或回滚)调用事件处理方法。
应用
使用场景
- 确保数据一致性:在事务成功提交后执行某些操作,以确保数据的一致性。例如,发送通知邮件或更新缓存。
- 延迟执行操作:在事务完成后执行一些非关键的操作,以减少事务的复杂性和执行时间。
- 事务回滚处理:在事务回滚时执行补偿逻辑或清理操作。
使用技巧
- 指定阶段:可以通过 phase 属性指定事件处理的阶段,如 AFTER_COMMIT、AFTER_ROLLBACK、AFTER_COMPLETION 等。
- 条件执行:可以使用 condition 属性来指定事件处理的条件。
- 异步执行:结合 @Async 注解,可以在事务完成后异步执行事件处理逻辑。
案例:
java
import org.springframework.context.event.EventListener;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.stereotype.Component;
@Component
public class MyEventListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handleEventAfterCommit(MyEvent event) {
// 事务提交后执行的逻辑
System.out.println("事务提交后处理事件: " + event.getMessage());
}
@TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void handleEventAfterRollback(MyEvent event) {
// 事务回滚后执行的逻辑
System.out.println("事务回滚后处理事件: " + event.getMessage());
}
}