You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring(非SpringBoot)中给RabbitMQ死信队列消息追加异常详情

在Spring非Boot环境下给RabbitMQ死信消息追加异常详情头

要实现把异常信息(比如异常消息、堆栈跟踪)加到死信队列的消息头里,咱们得自定义消息的错误处理逻辑——毕竟默认的RabbitMQ死信机制只会传递原消息的基础属性,不会自动附加异常详情。下面是适配你现有配置的具体实现步骤:

1. 自定义错误处理器捕获异常并修改消息头

先写一个RabbitListenerErrorHandler的实现类,它会在消息消费抛出异常时触发,我们可以在这里把异常信息塞进原消息的headers里,之后再让RabbitMQ的死信机制把带新headers的消息转去DLQ:

import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.RabbitListenerErrorHandler;
import org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException;
import org.springframework.stereotype.Component;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

@Component("customRabbitListenerErrorHandler")
public class CustomRabbitListenerErrorHandler implements RabbitListenerErrorHandler {

    @Override
    public Object handleError(Message message, org.springframework.messaging.Message<?> amqpMessage, ListenerExecutionFailedException exception) throws Exception {
        // 先拿到原消息的headers,为空就新建一个
        Map<String, Object> headers = new HashMap<>(message.getMessageProperties().getHeaders());
        
        // 把异常消息塞进headers
        headers.put("exception-message", exception.getCause().getMessage());
        // 把堆栈跟踪转成字符串也加进去
        StringWriter stackTraceWriter = new StringWriter();
        exception.getCause().printStackTrace(new PrintWriter(stackTraceWriter));
        headers.put("exception-stacktrace", stackTraceWriter.toString());
        
        // 更新原消息的headers
        message.getMessageProperties().setHeaders(headers);
        
        // 重新抛出异常,让RabbitMQ触发原生的死信机制
        throw exception;
    }
}

2. 给消息监听器绑定这个错误处理器

在你的@RabbitListener注解里指定刚写的错误处理器,这样消费异常时就会走咱们的自定义逻辑:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class TestMessageConsumer {

    @RabbitListener(queues = "test", errorHandler = "customRabbitListenerErrorHandler")
    public void processTestMessage(String messageContent) {
        // 这里模拟消息处理时抛出异常
        throw new RuntimeException("测试异常:消息处理失败,触发死信");
    }
}

3. (可选)手动发送死信(更灵活的方案)

如果你不想依赖RabbitMQ原生的死信交换机配置,也可以在错误处理器里手动把带异常头的消息发送到DLQ,这种方式能完全控制死信的内容和流向:

首先给错误处理器注入RabbitTemplate,然后手动发送:

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("customRabbitListenerErrorHandler")
public class CustomRabbitListenerErrorHandler implements RabbitListenerErrorHandler {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public Object handleError(Message message, org.springframework.messaging.Message<?> amqpMessage, ListenerExecutionFailedException exception) throws Exception {
        Map<String, Object> headers = new HashMap<>(message.getMessageProperties().getHeaders());
        headers.put("exception-message", exception.getCause().getMessage());
        
        StringWriter stackTraceWriter = new StringWriter();
        exception.getCause().printStackTrace(new PrintWriter(stackTraceWriter));
        headers.put("exception-stacktrace", stackTraceWriter.toString());
        
        message.getMessageProperties().setHeaders(headers);
        // 手动发送到你的DLQ队列
        rabbitTemplate.send("test.dlq", message);
        
        // 返回null表示消息已处理,不会触发重试(根据你的重试需求调整)
        return null;
    }
}

注意:如果用手动发送的方式,建议你去掉原队列queueTestx-dead-letter-exchangex-dead-letter-routing-key配置,避免同一消息被重复发送到DLQ。

验证死信的异常头

最后,你可以写一个DLQ的消费者,打印出消息头里的异常信息,确认是否生效:

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
public class DlqMessageConsumer {

    @RabbitListener(queues = "test.dlq")
    public void processDlqMessage(String messageContent, @Header Map<String, Object> headers) {
        System.out.println("收到死信消息内容:" + messageContent);
        System.out.println("异常详情:" + headers.get("exception-message"));
        System.out.println("异常堆栈:" + headers.get("exception-stacktrace"));
    }
}

这样就能在死信消息的headers里拿到完整的异常信息啦。


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

火山引擎 最新活动