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

基于Spring Advice的MQ Spring Boot PaaS应用全局异常处理实现咨询

实现Spring Boot MQ应用的全局异常处理(GlobalExceptionHandler)

我来给你梳理下怎么在你的Spring Boot PaaS MQ应用里实现这个全局异常处理类,刚好这类消息队列+数据库操作的场景我处理过不少,咱们一步步来落地:

1. 全局异常处理类的基础配置

首先要创建一个带有@RestControllerAdvice注解的类(如果你的应用是非Web场景,用@ControllerAdvice也可以),这个注解会让Spring自动识别它作为全局异常处理器。同时,如果是RabbitMQ/JMS这类消息队列,咱们还可以实现对应的消息监听异常处理器接口,确保消费消息时的异常也能被捕获。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.annotation.support.ListenerExecutionFailedException;
import org.springframework.rabbit.listener.api.RabbitListenerErrorHandler;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler implements RabbitListenerErrorHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    // 后续添加各异常处理方法...
}

2. 处理数据库相关RuntimeException

针对JPA操作中可能抛出的数据库RuntimeException(比如DataAccessException、OptimisticLockingFailureException),咱们写一个专门的处理方法,重点是记录详细日志,然后根据业务需求处理消息(比如转至死信队列、标记错误状态):

// 处理数据库操作相关的RuntimeException
@ExceptionHandler({DataAccessException.class, OptimisticLockingFailureException.class})
public void handleDatabaseRuntimeException(RuntimeException ex, Message<?> message) {
    logger.error("数据库操作失败,消息内容: {}", message.getPayload(), ex);
    
    // 示例业务处理:将异常消息转发至死信队列(以RabbitMQ为例)
    // rabbitTemplate.convertAndSend("dead-letter-exchange", "dead-letter-routing-key", message.getPayload());
    
    // 或者:构造错误响应发送到目标队列
    // ErrorResponse errorResp = new ErrorResponse("DB_ERROR", ex.getMessage());
    // rabbitTemplate.convertAndSend("target-exchange", "target-routing-key", errorResp);
}

3. 处理自定义业务异常

先定义一个自定义业务异常类,用来标记业务逻辑中的错误(比如参数非法、业务规则不满足):

public class BusinessException extends RuntimeException {
    private String errorCode;

    public BusinessException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }

    // getter & setter
}

然后在全局异常处理器中添加对应的处理方法:

// 处理自定义业务异常
@ExceptionHandler(BusinessException.class)
public void handleBusinessException(BusinessException ex, Message<?> message) {
    logger.warn("业务规则校验失败,错误码: {}, 消息内容: {}", ex.getErrorCode(), message.getPayload());
    
    // 示例:构造业务错误响应发送到目标队列
    // BusinessErrorResponse errorResp = new BusinessErrorResponse(ex.getErrorCode(), ex.getMessage());
    // rabbitTemplate.convertAndSend("target-exchange", "target-routing-key", errorResp);
}

4. 处理其他受检异常

对于剩下的受检异常(比如IOException、SQLException),咱们用一个通用的处理方法兜底,确保所有未被明确捕获的异常都能被处理:

// 处理其他未明确捕获的异常
@ExceptionHandler(Exception.class)
public void handleGenericException(Exception ex, Message<?> message) {
    logger.error("未预期的系统异常,消息内容: {}", message != null ? message.getPayload() : "无消息", ex);
    
    // 通用处理:比如发送告警通知、将消息标记为失败状态
}

5. 关联消息监听组件(以RabbitMQ为例)

为了让消息消费时的异常触发全局处理器,需要在@RabbitListener注解中指定异常处理器:

@RabbitListener(queues = "source-queue", errorHandler = "globalExceptionHandler")
public void consumeSourceMessage(MessagePayload payload) {
    // 业务逻辑:JPA数据库操作 → 构造响应 → 发送到目标队列
    // ...
}

关键注意点

  • 日志要详细:一定要记录异常栈和消息内容,方便后续排查问题
  • 消息处理策略:根据业务需求选择异常后的处理方式(重试、死信、返回错误响应)
  • 受检异常转换:业务代码中的受检异常,要么抛出,要么转换为RuntimeException,确保全局处理器能捕获到
  • JMS场景适配:如果用的是JMS,只需要实现JmsListenerErrorHandler接口,逻辑和RabbitMQ类似

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:58:50