Spring-AMQP Transactional发布没有异常

时间:2015-03-09 16:16:40

标签: java spring rabbitmq spring-amqp spring-rabbit

我正在尝试使用Spring-AMQP的Transactionnal RabbitMQ通道,但我想实际上吞下Exceptions来记录它们并能够恢复它们。

使用channelTransacted = true强制Channel也加入当前的transactionManager(在我的情况下是Hibernate),这会导致提交异常从@Transactionnal边界重新抛出,导致上层失败而无法捕获它并记录下来。

我还尝试手动将发布附加到事务处,因此只有在提交成功后才会执行:

public void publishFailSafeAfterSuccessfulTransaction(final String routingKey, final String message) {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            try {
                rabbitTemplate.convertAndSend(routingKey, message);
            } catch (Exception exception) {
                logger.error("Error while publishing message to RabbitMQ ");
            }
        }
});

以这种方式使用:

Entity entity = save(entity);
publishFailSafeAfterSuccessfulTransaction("routingkey", "Entity was updated");

但在这种情况下,我不能使用channelTransacted = true,因为它会将registeringSynchronization嵌套在另一个registeringSynchronization中,并且根本无法调用...

有没有办法实现这一目标?

更新:理想情况下,我想要覆盖ConnectionFactoryUtils类中使用的RabbitResourceSynchronization,但它是一个没有工厂实例化的私有类

TransactionSynchronizationManager.registerSynchronization(new RabbitResourceSynchronization(resourceHolder, connectionFactory, synched));

1 个答案:

答案 0 :(得分:1)

我实施的解决方案是在提交主事务后在新事务中进行发布。

第一个电话:

Entity entity = save(entity);
publishFailSafeAfterSuccessfulTransaction("routingkey", "Entity was updated");

此方法注册在主要事务提交后进行发布。

public void publishFailSafeAfterSuccessfulTransaction(final String routingKey, final String event) {

    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            try {
                publishFailSafe(routingKey, event);
            } catch (Exception exception) {
                //Do some recovering
            }
        }
    });
}

主要交易提交后,这个将进行发布。当通道被处理时,它将在提交新事务时提交消息,并且仅在该事务中失败并且错误将在先前方法中捕获。

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void publishFailSafe(String routingKey, String event) {
    try {
        rabbitTemplate.convertAndSend(routingKey.getRoutingKey(), event);
    } catch (Exception exception) {
        //Do some recovering
    }
}