用spring动态注册事务监听器?

时间:2011-03-18 20:33:39

标签: spring transactions jta

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

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

  // something like this
  getTransactionManager().registerPostCommitAction(new 
   TransactionSynchronizationAdapter() {
     public void afterCommit() { 
      notifyDownstream(); 
     }
  });
 }
}

Spring有一个TransactionSynchronization接口和适配器类,它看起来正是我想要的;但是,如何使用当前事务或事务管理器动态注册一个,并不是很明确。如果我能避免它,我宁愿不继承JtaTransactionManager。

问:之前是否有人这样做过。

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

4 个答案:

答案 0 :(得分:29)

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

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

答案 1 :(得分:3)

您可以在服务中使用aspect to match事务方法方面来完成此任务:

@Aspect
public class AfterReturningExample {

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

}

答案 2 :(得分:3)

这是一个更完整的解决方案,我做了类似的问题,想要在事务提交后发送我的消息(我本可以使用RabbitMQ TX,但它们相当慢)。

public class MessageBusUtils {
    public static Optional<MessageBusResourceHolder> getTransactionalResourceHolder(TxMessageBus messageBus) {

        if ( ! TransactionSynchronizationManager.isActualTransactionActive()) {
            return Optional.absent();
        }

        MessageBusResourceHolder o = (MessageBusResourceHolder) TransactionSynchronizationManager.getResource(messageBus);
        if (o != null) return Optional.of(o);

        o = new MessageBusResourceHolder();
        TransactionSynchronizationManager.bindResource(messageBus, o);
        o.setSynchronizedWithTransaction(true);
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new MessageBusResourceSynchronization(o, messageBus));
        }
        return Optional.of(o);

    }

    private static class MessageBusResourceSynchronization extends ResourceHolderSynchronization<MessageBusResourceHolder, TxMessageBus> {
        private final TxMessageBus messageBus;
        private final MessageBusResourceHolder holder;

        public MessageBusResourceSynchronization(MessageBusResourceHolder resourceHolder, TxMessageBus resourceKey) {
            super(resourceHolder, resourceKey);
            this.messageBus = resourceKey;
            this.holder = resourceHolder;
        }


        @Override
        protected void cleanupResource(MessageBusResourceHolder resourceHolder, TxMessageBus resourceKey,
                boolean committed) {
            resourceHolder.getPendingMessages().clear();
        }

        @Override
        public void afterCompletion(int status) {
            if (status == TransactionSynchronization.STATUS_COMMITTED) {
                for (Object o : holder.getPendingMessages()) {
                    messageBus.post(o, false);
                }
            }
            else {
                holder.getPendingMessages().clear();
            }
            super.afterCompletion(status);
        }


    }
}

public class MessageBusResourceHolder extends ResourceHolderSupport {

    private List<Object> pendingMessages = Lists.newArrayList();

    public void addMessage(Object message) {
        pendingMessages.add(message);
    }


    protected List<Object> getPendingMessages() {
        return pendingMessages;
    }

}

现在,在您实际发送信息的班级中,您将会这样做

@Override
public void postAfterCommit(Object o) {
    Optional<MessageBusResourceHolder> holder = MessageBusTxUtils.getTransactionalResourceHolder(this);
    if (holder.isPresent()) {
        holder.get().addMessage(o);
    }
    else {
        post(o, false);
    }
}

对于冗长的编码样本感到抱歉,但希望能在提交后向某人展示如何做某事。

答案 3 :(得分:0)

在提交和回滚方法上覆盖事务管理器是否有意义,在开头调用super.commit()