Spring事务同步器与事务监听器
在项目中,往往需要执行数据库操作后,发送消息或事件来异步调用其他组件执行相应的操作,例如:
- 用户注册后发送激活码;
- 配置修改后发送更新事件等。
但是,数据库的操作如果还未完成,此时异步调用的方法查询数据库发现没有数据,这就会出现问题。
为了解决上述问题,Spring
为我们提供了以下两种方式,以便我们可以在事务提交后再触发某一事件。
TransactionSynchronizationManager
事务同步管理器@TransactionalEventListener
注解
一、事务同步管理器 - TransactionSynchronizationManager
TransactionSynchronizationManager
是事务同步管理器。可以自定义实现TransactionSynchronization
类,来监听Spring
的事务操作。在事务执行前后可能需要做一些额外的操作这个时候就需要用到TransactionSynchronizationManager
去注入一个TransactionSynchronization
事务同步器,然后重写TransactionSynchronization
或者其子类的beforeCommit()
或者afterCommit()
方法,写入我们需要执行的业务。
public class StockServiceImpl implements StockService {
@Transactional(rollbackFor = Exception.class)
public void changeStock(Stock stock) {
//修改
stockMapper.updateById(stock);
//事务操作
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void beforeCommit(boolean readOnly) {
log.info("事务开始提交");
}
@Override
public void afterCommit() {
log.info("事务开始提交");
producer.sendMessageAync(NOTIFY, vo.getShopMdCode());
}
});
}
}
1.1 初始化事务同步器
在org.springframework.transaction.interceptor.TransactionInterceptor#invoke
中,对事务方法进行拦截处理。在createTransactionIfNecessary
创建TransactionInfo
对象时,会调用AbstractPlatformTransactionManager#prepareSynchronization
方法初始化事务同步器。
protected void prepareSynchronization(DefaultTransactionStatus status,
TransactionDefinition definition) {
if (status.isNewSynchronization()) {
// 用于保存当前事务是否还是 Active 状态
TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT
? definition.getIsolationLevel()
: null);
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
//初始化事务同步器
TransactionSynchronizationManager.initSynchronization();
}
}
1.1.1 TransactionSynchronizationManager在源码中的使用
在SpringCache
的自定义CacheManager
中。装饰Cache
对象使其支持事务操作。即只有在事务提交成功之后,才会进行缓存。
源码位置: org.springframework.cache.transaction.TransactionAwareCacheDecorator#put
@Override
public void put(final Object key, @Nullable final Object value) {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
TransactionSynchronizationManager.registerSynchronization(
new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
TransactionAwareCacheDecorator.this.targetCache.put(key, value);
}
});
} else {
this.targetCache.put(key, value);
}
}
connection
是线程不安全的,即需要为每一个数据库操作都获取一个Connection
对象。事务操作可以看做是一个整体,必须使用同一个Connection
进行操作。故在Spring
中使用LocalThread
(线程上下文)将Connection
对象和线程绑定。
在Spring
中的org.springframework.transaction.support.TransactionSynchronizationManager
类中,便是使用ThreadLocal
来为不同的事务线程提供独立的资源副本,并且同时维护这些事务的配置属性和运行状态。
1.1.2 Connection与TransactionSynchronizationManager关系
1. 请求事务方法时,调用doBegin()将事务信息保存到TransactionSynchronizationManager
中: 在该方法中主要流程是在数据库连接池中获取一个Connection
对象,然后将Connection
对象放入到ThreadLocal
中。实际上该事务方法的信息均由TransactionSynchronizationManager
类管理。
源码:org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
//在可见的数据源(连接池)中获取Connection对象
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
//...
//关闭Connection对象的自动提交
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
//将Connection对象绑定到Thread中
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(),
txObject.getConnectionHolder());
}
} catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction",
ex);
}
}
- 执行sql语句时,实际上通过
org.mybatis.spring.transaction.SpringManagedTransaction
类直接获取Connection
对象。
源码:org.mybatis.spring.transaction.SpringManagedTransaction#openConnection
private void openConnection() throws SQLException {
//在ThreadLocal中获取Connection对象
this.connection = DataSourceUtils.getConnection(this.dataSource);
this.autoCommit = this.connection.getAutoCommit();
//在ThreadLocal中获取是否开启事务
this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection,
this.dataSource);
//...
}
源码:org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//在doBegin()方法中,已经将创建的Connection对象放入到TransactionSynchronizationManager中
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
.getResource(dataSource);
if (conHolder != null
&& (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(fetchConnection(dataSource));
}
//直接返回Thread存储的Connection对象。
return conHolder.getConnection();
}
//...
return con;
}
下面我们来分析一下事务操作对于连接资源的处理,也就是事务处理中TransactionSynchronizationManager
对于资源(resources
属性)的管理。
public abstract class TransactionSynchronizationManager {
// 线程上下文中保存着【线程池对象:ConnectionHolder】的Map对象。线程可以通过该属性获取到同一个Connection对象。
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 事务同步器,是Spring交由程序员进行扩展的代码,每个线程可以注册N个事务同步器。
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
// 当前事务的名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 当前事务是否是只读
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
// 事务的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
// 事务是否开启 actual:真实的
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
// 将Connection对象绑定到resources上。
Object oldValue = map.put(actualKey, value);
//...
}
}
这个对象里面通过ThreadLocal
保存了线程需要状态以及资源对象。
- resources:保存连接资源,因为一个方法里面可能包含两个事务(比如事务传播特性为
TransactionDefinition#PROPAGATION_REQUIRES_NEW
),所以就用Map
来保存资源. - synchronizations:线程同步器,在进行数据库操作的时候,如果需要多个操作要么一起成功,要么一起失败那么就需要使用事务操作了。使用
Spring
框架只需要在方法上添加@Transactional
注解这个方法就具有事务特性了。而且Spring
也事务操作给开发者提供了很方便的扩展。这个就是对Spring
事务的扩展,通过TransactionSynchronizationManager#registerSynchronization
来注册,我们稍后来分析这个对象在进行数据库操作的时候,如果需要多个操作要么一起成功,要么一起失败那么就需要使用事务操作了。使用Spring
框架只需要在方法上添加@Transactional
注解这个方法就具有事务特性了。而且Spring
也事务操作给开发者提供了很方便的扩展。 - currentTransactionReadOnly:用于保存当前事务是否只读。在进行数据库操作的时候,如果需要多个操作要么一起成功,要么一起失败那么就需要使用事务操作了。使用
Spring
框架只需要在方法上添加@Transactional
注解这个方法就具有事务特性了。而且Spring
也事务操作给开发者提供了很方便的扩展。 - currentTransactionName:用于保存当前事务名称,默认为空
- currentTransactionIsolationLevel:用来保存当前事务的隔离级别
- actualTransactionActive:用于保存当前事务是否还是
Active
状态
Spring
对于事务的管理都是基于TransactionSynchronizationManager
。
1.2 TransactionSynchronization事务的扩展
事务操作的时候它的当前线程还保存了TransactionSynchronization
对象。而这个对象伴随着Spring
对事务处理的各个生命周期都会有相应的扩展。这个类是程序员对事务同步的扩展点:用于事务同步回调的接口。
public interface TransactionSynchronization extends Flushable {
/** Completion status in case of proper commit. */
// 事务提交状态
int STATUS_COMMITTED = 0;
/** Completion status in case of proper rollback. */
// 事务回滚状态
int STATUS_ROLLED_BACK = 1;
/** Completion status in case of heuristic mixed completion or system errors. */
// 事务异常状态
int STATUS_UNKNOWN = 2;
/**
* 当前事务挂起时触发
* Supposed to unbind resources from TransactionSynchronizationManager if managing any.
* @see org.springframework.transaction.reactive.TransactionSynchronizationManager#unbindResource
*/
default void suspend() {
}
/**
* 当前事务恢复时触发(结束挂起时)
* Supposed to rebind resources to TransactionSynchronizationManager if managing any.
* @see org.springframework.transaction.reactive.TransactionSynchronizationManager#bindResource
*/
default void resume() {
}
/**
* 当前事务刷新时触发
* 将基础会话刷新到数据存储区(如果适用),比如Hibernate/JPA的Session
* @see org.springframework.transaction.TransactionStatus#flush
*/
@Override
default void flush() {
}
/**
* 当前事务提交前触发,此处若发生异常,会导致回滚。
* @see #beforeCompletion
*/
default void beforeCommit(boolean readOnly) {
}
/**
* 当前事务完成前触发。
* 在beforeCommit之后,commit/rollback之前执行。即使异常,也不会回滚。
* @see #beforeCommit
* @see #afterCompletion
*/
default void beforeCompletion() {
}
/**
* 当前事务提交后触发
*/
default void afterCommit() {
}
/**
* 当前事务完成后触发
* 通过status的value指定具体的触发时机(即上面的三个属性)
*/
default void afterCompletion(int status) {
}
}
在TransactionSynchronization
使用最多的是afterCommit
和afterCompletion
方法。可以在事务执行完毕之后,直接调用afterCommit()
方法进行异步通知。在doCommit()
方法中提交事务后,在cleanupAfterCompletion
对connection
进行重置,即我们依旧可以在afterCommit()
回调中对数据库进行操作。
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
//提交事务
doCommit(status);
//...
try {
//回调所有事务同步器的afterCommit方法。
triggerAfterCommit(status);
}
finally {
//回调所有事务同步器的afterCompletion方法。
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
//清除TransactionSynchronizationManager的ThreadLocal绑定的数据。
//解除Thread绑定的resources资源。
//将Commit设置为自动提交。
//清理ConnectionHolder资源。
cleanupAfterCompletion(status);
}
}
1.3 案例
1.3.1 afterCompletion
@Transactional
public void handle() {
try {
// 业务逻辑
} catch(Exception e) {
// 事务回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
// 事务完成后触发, 可以根据status的value判断外部事务执行状态
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCompletion(int status) {
switch (status) {
case 0:
// 外部方法事务提交后执行的业务逻辑
break;
case 1:
// 外部方法事务回滚后执行的业务逻辑
break;
case 2:
// 外部方法事务异常时执行的业务逻辑
break;
}
}
});
}
1.3.2 afterCommit
@Transactional
public void handle() {
// 业务逻辑
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
@Override
public void afterCommit() {
// 外部事务提交后执行的业务逻辑
}
});
}
二、事务监听器 - TransactionalEventListener
在Spring framework 4.2
之后还可以使用@TransactionalEventListener
处理数据库事务提交成功后再执行操作。Spring
的发布订阅模型实际上并不是异步的,而是同步的来将代码进行解耦。而TransactionEventListener
仍是通过这种方式,只不过加入了回调的方式来解决,这样就能够在事务进行Commited
,Rollback
…的时候才会去进行Event
的处理。这种方式比TransactionSynchronization
更加优雅。
2.1 使用方式
它的使用方式如下:
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private MqService mqService;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Transactional
@Override
public Object finishOrder(Order order) {
// 修改订单成功
orderMapper.updateOrderSuccess(order);
// 发布一个自定义的事件~
applicationEventPublisher.publishEvent(new MyAfterTransactionEvent(this, order));
return "success";
}
// 事务监听器
@Slf4j
@Component
private static class MyTransactionListener {
@TransactionalEventListener(
// 监听的阶段
phase = TransactionPhase.AFTER_COMMIT,
// 监听的事件
classes = MyAfterTransactionEvent.class)
private void onFinishOrderEvent(MyAfterTransactionEvent event) {
Object source = event.getSource();
Order order = event.getOrder();
mqService.send(order);
// 它肯定是在上面事务提交之后才会执行的
log.info(source + ":" + JSONObject.toString(order));
}
}
// 自定义一个事件,继承自ApplicationEvent
private static class MyAfterTransactionEvent extends ApplicationEvent {
// 发布事件需要的参数
private Order order;
/**
* 事件的构造方法
* @param source 发布源,也就是发布事件的对象
* @param payload 参数
*/
public MyAfterTransactionEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() {
return order;
}
}
}
关于上述属性中的TransactionPhase
,其可以取如下几个类型的值:
public enum TransactionPhase {
//指定目标方法在事务commit之前执行
BEFORE_COMMIT,
//指定目标方法在事务commit之后执行
AFTER_COMMIT,
//指定目标方法在事务rollback之后执行
AFTER_ROLLBACK,
//指定目标方法在事务完成时执行,这里的完成是指无论事务是成功提交还是事务回滚了
AFTER_COMPLETION;
}
2.2 TransactionalEventListener
// @since 4.2 显然,注解的方式提供得还是挺晚的,而API的方式第一个版本就已经提供了
// 另外最重要的是,它头上有一个注解:@EventListener
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EventListener //有类似于注解继承的效果
public @interface TransactionalEventListener {
// 指定当前标注方法处理事务的类型
// 需要注意的是: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;
// 指定目标方法是否是所支持的监听器的类型,这里的判断逻辑就是如果目标方法上包含有
// TransactionalEventListener注解,则说明其是一个事务事件监听器
@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
,最终注册进事件发射器的容器里面
2.3 ApplicationListenerMethodTransactionalAdapter
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) {
// 如果当前TransactionManager已经配置开启事务事件监听,
// 此时才会注册TransactionSynchronization对象
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 通过当前事务事件发布的参数,创建一个TransactionSynchronization对象
TransactionSynchronization transactionSynchronization =
createTransactionSynchronization(event);
// 注册TransactionSynchronization对象到TransactionManager中
TransactionSynchronizationManager.registerSynchronization(transactionSynchronization);
}
// 若fallbackExecution=true,那就是表示即使没有事务 也会执行handler
else if (this.annotation.fallbackExecution()) {
// 如果当前TransactionManager没有开启事务事件处理,但是当前事务监听方法中配置了
// fallbackExecution属性为true,说明其需要对当前事务事件进行监听,无论其是否有事务
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();
}
// 最终都是委托给了listener来真正的执行处理来执行最终处理逻辑(也就是解析classes、condition、执行方法体等等)
@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);
}
}
}
可以看到,对于事务事件的处理,最终都是委托给了ApplicationListenerMethodAdapter.processEvent()
方法进行的。如下是该方法的源码:
public class ApplicationListenerMethodAdapter implements GenericApplicationListener {
//...
public void processEvent(ApplicationEvent event) {
// 处理事务事件的相关参数,这里主要是判断TransactionalEventListener注解中是否配置了value
// 或classes属性,如果配置了,则将方法参数转换为该指定类型传给监听的方法;如果没有配置,则判断
// 目标方法是ApplicationEvent类型还是PayloadApplicationEvent类型,是则转换为该类型传入
Object[] args = resolveArguments(event);
// 这里主要是获取TransactionalEventListener注解中的condition属性,然后通过
// Spring expression language将其与目标类和方法进行匹配
if (shouldHandle(event, args)) {
// 通过处理得到的参数借助于反射调用事务监听方法
Object result = doInvoke(args);
if (result != null) {
// 对方法的返回值进行处理
handleResult(result);
} else {
logger.trace("No result object given - no result to handle");
}
}
}
// 处理事务监听方法的参数
protected Object[] resolveArguments(ApplicationEvent event) {
// 获取发布事务事件时传入的参数类型
ResolvableType declaredEventType = getResolvableType(event);
if (declaredEventType == null) {
return null;
}
// 如果事务监听方法的参数个数为0,则直接返回
if (this.method.getParameterCount() == 0) {
return new Object[0];
}
// 如果事务监听方法的参数不为ApplicationEvent或PayloadApplicationEvent,则直接将发布事务
// 事件时传入的参数当做事务监听方法的参数传入。从这里可以看出,如果事务监听方法的参数不是
// ApplicationEvent或PayloadApplicationEvent类型,那么其参数必须只能有一个,并且这个
// 参数必须与发布事务事件时传入的参数一致
Class<?> eventClass = declaredEventType.getRawClass();
if ((eventClass == null || !ApplicationEvent.class.isAssignableFrom(eventClass))
&& event instanceof PayloadApplicationEvent) {
return new Object[] {((PayloadApplicationEvent) event).getPayload()};
} else {
// 如果参数类型为ApplicationEvent或PayloadApplicationEvent,则直接将其传入事务事件方法
return new Object[] {event};
}
}
// 判断事务事件方法方法是否需要进行事务事件处理
private boolean shouldHandle(ApplicationEvent event, @Nullable Object[] args) {
if (args == null) {
return false;
}
String condition = getCondition();
if (StringUtils.hasText(condition)) {
Assert.notNull(this.evaluator, "EventExpressionEvaluator must no be null");
EvaluationContext evaluationContext = this.evaluator.createEvaluationContext(
event, this.targetClass, this.method, args, this.applicationContext);
return this.evaluator.condition(condition, this.methodKey, evaluationContext);
}
return true;
}
// 对事务事件方法的返回值进行处理,这里的处理方式主要是将其作为一个事件继续发布出去,这样就可以在
// 一个统一的位置对事务事件的返回值进行处理
protected void handleResult(Object result) {
// 如果返回值是数组类型,则对数组元素一个一个进行发布
if (result.getClass().isArray()) {
Object[] events = ObjectUtils.toObjectArray(result);
for (Object event : events) {
publishEvent(event);
}
} else if (result instanceof Collection<?>) {
// 如果返回值是集合类型,则对集合进行遍历,并且发布集合中的每个元素
Collection<?> events = (Collection<?>) result;
for (Object event : events) {
publishEvent(event);
}
} else {
// 如果返回值是一个对象,则直接将其进行发布
publishEvent(result);
}
}
//...
}
总结而言,就是包装@TransactionalEventListener
注解的方法,通过TransactionalEventListenerFactory#createApplicationListener
添加适配器ApplicationListenerMethodTransactionalAdapter
,内部通过TransactionSynchronizationManager.registerSynchronization
注册一个同步器发布事务时,记下event
,然后注册一个同步器TransactionSynchronizationEventAdapter
,当事务提交后, TransactionSynchronizationManager
会回调上面注册的同步适配器,这里注册就是放入到一个ThreadLocal
里面,通过它来传递参数。这时TransactionSynchronizationEventAdapter
内部才会真正的去调用onHelloEvent
方法。
从源码里可以看出,其实@TransactionalEventListener
的底层实现原理还是事务同步器:TransactionSynchronization
和TransactionSynchronizationManager
。上面就是使用@TransactionalEventListener
处理数据库事务提交成功后再执行操作的原理。