You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring AMQP:发布至不存在交换机的事务异常处理疑问

问题:Spring AMQP中@Transactional包裹RabbitTemplate发送逻辑时,不存在的Exchange未抛出预期异常

我正在处理生产者向不存在的DirectExchange发送消息的场景。根据spring-amqp官方文档说明:

要在发送线程检测异常,可在RabbitTemplate上设置setChannelTransacted(true),异常会在txCommit()时被检测到。但事务会显著影响性能,因此仅为此场景启用事务前需谨慎考量。

按文档设置rabbitTemplate.setChannelTransacted(true)后,出现了不符合预期的现象:

  • 当rabbitTemplate.convertAndSend未被org.springframework.transaction.annotation.Transactional注解包裹时,能在txCommit()时抛出预期的异常;
  • 当该方法被@Transactional注解包裹时,仅会静默输出错误日志,不会抛出异常。

我的业务逻辑需要先执行数据库操作,因此必须用@Transactional注解包裹发送方法,想确认这种行为是框架预期的,还是我的配置存在问题。

相关代码配置

RabbitTemplate Bean配置

@Bean
RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory) {
    
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
    rabbitTemplate.setReturnsCallback(new ReturnsCallback() {
        
        @Override
        public void returnedMessage(ReturnedMessage returned) {
            //routingKey doesn't exist, notify and send to parking lot...
        }
    });
    rabbitTemplate.setMandatory(true);
    rabbitTemplate.setChannelTransacted(true);
    rabbitTemplate.setExchange("some.exchange");
    
    return rabbitTemplate;
}

消息发布方法

@Override
@Transactional
public void publishMessage() {
    
    // database processing...
    rabbitTemplate.convertAndSend("myRoutingKey", "myMessage");
}

现象详情

带@Transactional注解时的日志输出

ERROR o.s.a.r.c.CachingConnectionFactory [AbstractConnectionFactory.java:748] Shutdown Signal: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'some.exchange' in vhost '/consume', class-id=60, method-id=40)

不带@Transactional注解时的异常栈

Caused by: org.springframework.amqp.AmqpIOException: java.io.IOException
        at org.springframework.amqp.rabbit.connection.RabbitUtils.commitIfNecessary(RabbitUtils.java:144)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.doSend(RabbitTemplate.java:2398)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.lambda$send$3(RabbitTemplate.java:1064)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.invokeAction(RabbitTemplate.java:2229)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.doExecute(RabbitTemplate.java:2188)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.execute(RabbitTemplate.java:2140)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.send(RabbitTemplate.java:1063)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:1128)
        at org.springframework.amqp.rabbit.core.RabbitTemplate.convertAndSend(RabbitTemplate.java:1110)
        at gov.osc.lgmm.service.core.impl.CoreServiceImpl.sendFilingStatus(CoreServiceImpl.java:120)
        ... 75 common frames omitted
Caused by: java.io.IOException: null
        at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:129)
        at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:125)
        at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:147)
        at com.rabbitmq.client.impl.ChannelN.txCommit(ChannelN.java:1540)
        at com.rabbitmq.client.impl.ChannelN.txCommit(ChannelN.java:46)
        at org.springframework.amqp.rabbit.connection.PublisherCallbackChannelImpl.txCommit(PublisherCallbackChannelImpl.java:633)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:90)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
        at java.lang.reflect.Method.invoke(Method.java:508)
        at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:1157)
        at com.sun.proxy.$Proxy185.txCommit(Unknown Source)
        at org.springframework.amqp.rabbit.connection.RabbitUtils.commitIfNecessary(RabbitUtils.java:141)
        ... 84 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'some.exchange' in vhost '/consume', class-id=60, method-id=40)
        at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66)
        at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:36)
        at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:502)
        at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:293)
        at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:141)
        ... 94 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'some.exchange' in vhost '/consume', class-id=60, method-id=40)
        at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:517)
        at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:341)
        at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:182)
        at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:114)
        at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:739)
        at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47)
        at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:666)
        ... 1 common frames omitted

环境信息

  • Spring Boot版本:2.5.2
  • Spring AMQP版本:2.3.9
  • 事务管理器:JpaTransactionManager

内容的提问来源于stack exchange,提问作者Imperious

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 08:02:58