Spring事务同步器与事务监听器

在项目中,往往需要执行数据库操作后,发送消息或事件来异步调用其他组件执行相应的操作,例如:

  • 用户注册后发送激活码;
  • 配置修改后发送更新事件等。

但是,数据库的操作如果还未完成,此时异步调用的方法查询数据库发现没有数据,这就会出现问题。

为了解决上述问题,Spring为我们提供了以下两种方式,以便我们可以在事务提交后再触发某一事件。

  1. TransactionSynchronizationManager事务同步管理器
  2. @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);
    }
}
  1. 执行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使用最多的是afterCommitafterCompletion方法。可以在事务执行完毕之后,直接调用afterCommit()方法进行异步通知。doCommit()方法中提交事务后,在cleanupAfterCompletionconnection进行重置,即我们依旧可以在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仍是通过这种方式,只不过加入了回调的方式来解决,这样就能够在事务进行CommitedRollback…的时候才会去进行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的底层实现原理还是事务同步器:TransactionSynchronizationTransactionSynchronizationManager。上面就是使用@TransactionalEventListener处理数据库事务提交成功后再执行操作的原理。

参考文章

posted @ 2022-04-25 16:50  夏尔_717  阅读(2595)  评论(0编辑  收藏  举报