TransactionalEventListener实现事务监控

问题背景

在项目中,往往需要执行数据库操作后,发送消息或事件来异步调用其他组件执行相应的操作,例如:
用户注册后发送激活码;
配置修改后发送更新事件等。
但是,数据库的操作如果还未完成,此时异步调用的方法查询数据库发现没有数据,这就会出现问题。

为了解决上述问题,Spring为我们提供了两种方式:
(1) @TransactionalEventListener注解
(2) 事务同步管理器TransactionSynchronizationManager
以便我们可以在事务提交后再触发某一事件。

1. @TransactionalEventListener注解

在Spring4.2+,有一种叫做TransactionEventListener的方式,能够控制在事务的时候Event事件的处理方式。
我们知道,Spring的发布订阅模型实际上并不是异步的,而是同步的来将代码进行解耦。而TransactionEventListener仍是通过这种方式,只不过加入了回调的方式来解决,这样就能够在事务进行Commited,Rollback…等的时候才会去进行Event的处理。
代码如下:

@Service("fooService") 
public class FooServiceImpl implements FooService {
    private static final Logger LOGGER = Logger.getLogger(FooServiceImpl.class); 
    @Override 
    public void insertFoo(Foo foo) throws MyTransactionException { 
    	LOGGER.info("[fooService] start insert foo"); 
    	ApplicationEventPublisher eventPublisher = EventPublisher.getApplicationEventPublisher(); 
    	if (null != eventPublisher) { 
    	    eventPublisher.publishEvent(new MyTransactionEvent("test", this)); 
    	} 
        LOGGER.info("[fooServive] finish insert foo"); 
    } 
} 

public class MyTransactionEvent extends ApplicationEvent { 
    private String name; 
    public MyTransactionEvent(String name, Object source) { 
        super(source); 
        this.name = name; 
    } 
    public String getName() { 
        return this.name; 
    } 
} 

@Component 
public class MyTransactionListener { 
    private static final Logger LOGGER = Logger.getLogger(MyTransactionListener.class);       
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) 
    public void hanldeOrderCreatedEvent(MyTransactionEvent event) { 
        LOGGER.info("transactionEventListener start"); 
        // do transaction event 
        LOGGER.info("event : " + event.getName());
        // finish transaction event
        LOGGER.info("transactionEventListener finish"); 
    } 
}

这样,只有当前事务提交之后,才会执行事件监听器的方法。其中参数phase默认为AFTER_COMMIT,共有四个枚举:

/** 
* Fire the event before transaction commit. 
* @see TransactionSynchronization#beforeCommit(boolean) */ 
BEFORE_COMMIT, 
/** 
* Fire the event after the commit has completed successfully. 
* <p>Note: This is a specialization of {@link #AFTER_COMPLETION} and 
* therefore executes in the same after-completion sequence of events, 
* (and not in {@link TransactionSynchronization#afterCommit()}). 
* @see TransactionSynchronization#afterCompletion(int) 
* @see TransactionSynchronization#STATUS_COMMITTED */ AFTER_COMMIT, 
/** 
* Fire the event if the transaction has rolled back. 
* <p>Note: This is a specialization of {@link #AFTER_COMPLETION} and 
* therefore executes in the same after-completion sequence of events. 
* @see TransactionSynchronization#afterCompletion(int) 
* @see TransactionSynchronization#STATUS_ROLLED_BACK 
*/ 
AFTER_ROLLBACK, 
/** 
* Fire the event after the transaction has completed. 
* <p>For more fine-grained events, use {@link #AFTER_COMMIT} or 
* {@link #AFTER_ROLLBACK} to intercept transaction commit 
* or rollback, respectively. 
* @see TransactionSynchronization#afterCompletion(int) */ 
AFTER_COMPLETION

内部实现就是包装@TransactionalEventListener注解的方法,添加了一个适配器, ApplicationListenerMethodTransactionalAdapter,内部通过TransactionSynchronizationManager.registerSynchronization 注册一个同步器发布事务时,,记下event,然后注册一个同步器TransactionSynchronizationEventAdapter,当事务提交后, TransactionSynchronizationManager会回调上面注册的同步适配器,这里注册就是放入到一个ThreadLocal里面,通过它来传递参数。这时,TransactionSynchronizationEventAdapter内部才会真正的去调用hanldeOrderCreatedEvent方法。

2. TransactionSynchronizationManager方法

这种方法是通过手动的来注册回调来实现的。

@EventListener 
public void afterRegisterSendMail(MessageEvent event) { 
    // Spring 4.2 之前 
    TransactionSynchronizationManager.registerSynchronization(
        new TransactionSynchronizationAdapter() { 
        @Override 
        public void afterCommit() { 
            internalSendMailNotification(event); 
        } 
    }); 
}

@TransactionalEventListener底层也是这样实现的。

  • 10
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值