基于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
相关产品推荐
相关产品推荐

