使用spring动态注册事务侦听器?

使用spring动态注册事务侦听器?,spring,transactions,jta,Spring,Transactions,Jta,我有一个springframework应用程序,我想在其中为当前正在进行的事务添加一个事务侦听器。其动机是触发一个提交后操作,通知下游系统。我正在使用@Transactional围绕某个服务方法包装一个事务——这就是我想要创建/注册事务后侦听器的地方。我想做一些“像”下面的事情 public class MyService { @Transaction public void doIt() { modifyObjects(); // something like this ge

我有一个springframework应用程序,我想在其中为当前正在进行的事务添加一个事务侦听器。其动机是触发一个提交后操作,通知下游系统。我正在使用@Transactional围绕某个服务方法包装一个事务——这就是我想要创建/注册事务后侦听器的地方。我想做一些“像”下面的事情

public class MyService {
 @Transaction
 public void doIt() {
  modifyObjects();

  // something like this
  getTransactionManager().registerPostCommitAction(new 
   TransactionSynchronizationAdapter() {
     public void afterCommit() { 
      notifyDownstream(); 
     }
  });
 }
}
Spring有一个TransactionSynchronization接口和适配器类,这似乎正是我想要的;但是,目前还不清楚如何在当前事务或事务管理器中动态注册。如果可以避免的话,我宁愿不要将JtaTransactionManager子类化

Q:以前有人这样做过吗

Q:注册我的适配器最简单的方法是什么?

您可以在服务中使用事务方法方面来完成这一点:

@Aspect
public class AfterReturningExample {

  @AfterReturning("execution(* com.mypackage.MyService.*(..))")
  public void afterReturning() {
    // ...
  }

}

其实没有我想的那么难,;spring有一个静态助手类,它将“正确的”内容放入线程上下文中

TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            s_logger.info("TRANSACTION COMPLETE!!!");
        }
    }
);

这里有一个更完整的解决方案,是我为一个类似的问题所做的,即希望在事务提交后发送消息(我可以使用RabbitMQ TX,但它们相当慢)

公共类MessageBusUtils{
公共静态可选getTransactionalResourceHolder(TxMessageBus messageBus){
如果(!TransactionSynchronizationManager.isActualTransactionActive()){
返回可选的。缺席();
}
MessageBusResourceHolder o=(MessageBusResourceHolder)TransactionSynchronizationManager.getResource(messageBus);
如果(o!=null),则返回可选的(o);
o=新的MessageBusResourceHolder();
TransactionSynchronizationManager.bindResource(messageBus,o);
o、 设置SynchronizedWithTransaction(true);
if(TransactionSynchronizationManager.isSynchronizationActive()){
TransactionSynchronizationManager.registerSynchronization(新MessageBusResourceSynchronization(o,messageBus));
}
返回可选。of(o);
}
私有静态类MessageBusResourceSynchronization扩展了ResourceHolderSynchronization{
专用最终TxMessageBus messageBus;
私人最终信息持有人;
public MessageBusResourceSynchronization(MessageBusResourceHolder resourceHolder,TxMessageBus resourceKey){
超级(resourceHolder,resourceKey);
this.messageBus=resourceKey;
this.holder=资源持有者;
}
@凌驾
受保护的无效清除资源(MessageBusResourceHolder resourceHolder、TxMessageBus resourceKey、,
布尔值(已提交){
resourceHolder.getPendingMessages().clear();
}
@凌驾
完成后公共作废(int状态){
如果(状态==事务同步。状态_已提交){
对于(对象o:holder.getPendingMessages()){
messageBus.post(o,false);
}
}
否则{
holder.getPendingMessages().clear();
}
超级。完成后(状态);
}
}
}
公共类MessageBusResourceHolder扩展ResourceHolderSupport{
私有列表pendingMessages=Lists.newArrayList();
公共无效添加消息(对象消息){
pendingMessages.add(消息);
}
受保护列表getPendingMessages(){
返回挂起消息;
}
}
现在在你的课堂上,你实际发送的信息,你会做

@Override
public void postAfterCommit(Object o) {
    Optional<MessageBusResourceHolder> holder = MessageBusTxUtils.getTransactionalResourceHolder(this);
    if (holder.isPresent()) {
        holder.get().addMessage(o);
    }
    else {
        post(o, false);
    }
}
@覆盖
公共void postAfterCommit(对象o){
可选holder=MessageBusTxUtils.getTransactionalResourceHolder(this);
if(holder.isPresent()){
holder.get().addMessage(o);
}
否则{
邮政(o,假);
}
}

对于冗长的编码示例,我很抱歉,但希望这将向某人展示如何在提交后执行操作。

在提交和回滚方法上覆盖事务管理器,在开始时调用
super.commit()

这是一个很好的建议,但是,这不会在任何事务中执行吗?我只想圆满完成。另外,我可以将这些AOP注释与默认spring(我没有使用代码编织)一起使用,只使用JDK代理。当方法抛出异常时,返回建议不会运行,因此这依赖于@Transactional committing when method返回结果并在抛出异常时回滚,这通常是会发生的。这些方面是通过spring动态代理调用的,因此它不会进行任何代码编织(除非您没有为spring到代理提供接口,spring将在运行时使用cglib编织代码)。+1表示有趣,但如果不进行测试,我仍然不相信。至少有2个@AfterReturning涉及:@事务性,然后是我的自定义特性。如果@Transactional运行,那么我的运行一切正常;然而,在前面我将执行的另一个顺序中——独立于事务提交状态。+1是一个简单明了的答案。我不知道TransactionSynchronizationManager存在。事实上,这个解决方案并没有我想象的那么好。TransactionSynchronizationManager的契约更广泛,尝试从afterCommit()中发送JMS消息失败(没有例外),因为上面的代码确实遵循契约允许您在事务管理器中插入它们,以便两个系统(db、MessageBroker)之间的事务同步。我不想这样做,因为RabbitMQ TX非常慢。因此,您可能想看看我的解决方案。我正在使用您的代码在事务提交后更新3Solr索引。我还使用Spring事件来检测业务对象的修改,将事件存储在ResourceHolder中,并更新inde
@Override
public void postAfterCommit(Object o) {
    Optional<MessageBusResourceHolder> holder = MessageBusTxUtils.getTransactionalResourceHolder(this);
    if (holder.isPresent()) {
        holder.get().addMessage(o);
    }
    else {
        post(o, false);
    }
}