自定义ExceptionHandler导致Resilience4j的@CircuitBreaker与@Retry不触发
解决@CircuitBreaker/@Retry与自定义响应模型的冲突问题
方案1:业务层主动抛出异常,异常处理器统一转换响应
既然@CircuitBreaker和@Retry需要异常触发,那就不在业务逻辑层直接返回自定义响应实体,而是在业务执行失败时抛出特定业务异常,让容错机制先捕获异常执行逻辑,再由CustomExceptionHandler把异常转换成自定义响应返回给前端。
示例代码:
1.1 定义业务异常
public class ServiceCallFailedException extends RuntimeException { public ServiceCallFailedException(String message) { super(message); } }
1.2 业务方法抛出异常(配合容错注解)
@Service public class RemoteService { @CircuitBreaker(name = "remoteService", fallbackMethod = "fallbackCall") @Retry(name = "remoteService", retryExceptions = ServiceCallFailedException.class) public String callThirdParty() { // 模拟第三方服务调用失败 boolean callFailed = true; if (callFailed) { throw new ServiceCallFailedException("第三方服务调用超时"); } return "正常响应数据"; } public String fallbackCall(Throwable throwable) { return "熔断降级返回数据"; } }
1.3 异常处理器转换响应
@ControllerAdvice public class CustomExceptionHandler { @ExceptionHandler(ServiceCallFailedException.class) public ResponseEntity<CustomResponse> handleServiceException(ServiceCallFailedException e) { CustomResponse response = new CustomResponse(); response.setCode(500); response.setMessage(e.getMessage()); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } }
方案2:基于响应结果配置容错触发条件(无需抛出异常)
如果不想改动现有业务逻辑的返回结构,可以利用Resilience4j(主流容错框架)的自定义断言,让熔断/重试逻辑根据自定义响应实体的状态来触发,而非依赖异常。
示例:配置CircuitBreaker根据响应结果判断是否触发熔断
@Service public class RemoteService { @CircuitBreaker( name = "remoteService", fallbackMethod = "fallbackCall", circuitBreakerConfig = @CircuitBreakerConfig( predicate = "responsePredicate" ) ) public CustomResponse callThirdParty() { // 直接返回自定义响应,比如失败状态的响应 CustomResponse failedResponse = new CustomResponse(); failedResponse.setCode(500); failedResponse.setMessage("服务调用失败"); return failedResponse; } public CustomResponse fallbackCall(CustomResponse response, Throwable throwable) { CustomResponse fallbackResponse = new CustomResponse(); fallbackResponse.setCode(200); fallbackResponse.setMessage("降级返回数据"); return fallbackResponse; } // 自定义断言:判断响应是否为失败状态 public static Predicate<CustomResponse> responsePredicate() { return response -> response.getCode() == 500; } }
Retry同理,可以配置retryOnResult属性,指定判断响应是否需要重试的逻辑。
方案3:缩小异常处理器的拦截范围
调整CustomExceptionHandler的拦截范围,只处理Controller层抛出的异常,让业务层的异常(或响应中的错误状态)先被容错机制捕获。
比如限制异常处理器只处理当前Controller包下的类:
@ControllerAdvice(basePackages = "com.yourproject.controller") public class CustomExceptionHandler { // 仅处理Controller层抛出的异常,业务层异常留给容错机制处理 @ExceptionHandler(Exception.class) public ResponseEntity<CustomResponse> handleControllerExceptions(Exception e) { // 转换为自定义响应 CustomResponse response = new CustomResponse(); response.setCode(500); response.setMessage(e.getMessage()); return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR); } }
这样业务层的异常不会被提前拦截,@CircuitBreaker和@Retry能正常捕获并执行逻辑,最终异常还是会被Controller层抛出后由处理器转换为自定义响应。
内容的提问来源于stack exchange,提问作者Julio Vargas
相关产品推荐
相关产品推荐

