非HTTP内部调用如何复用@ControllerAdvice异常处理逻辑
是否存在无需发起真实HTTP请求,直接在代码内部生成API端点被调用时返回的JSON响应的方案?
期望实现效果为:应用内部直接调用自身Controller方法,直接生成JSON格式响应字符串,不经过HTTP调用流程。
直接调用Controller方法后通过ObjectMapper序列化返回值,可以正常获取成功场景的响应结果,但如果方法执行抛出异常,异常会直接向外抛出,无法触发@ControllerAdvice中定义的异常处理器生成对应的标准错误响应。需要确认:是否可以在应用内部(不发起HTTP请求)将捕获到的异常交给@ControllerAdvice定义的异常处理器处理,生成和真实接口调用完全一致的错误响应?
当前开发场景为批量API功能:用户无需多次调用单个API,只需将多个请求载荷组成列表传入批量API即可,内部需要将每个子请求的响应结果持久化到批量API对应的数据库实体中,因此要求每个子请求返回的JSON响应和原API被真实HTTP调用时完全一致。如果单独为批量API编写异常处理逻辑,会和@ControllerAdvice中已有的异常处理代码重复,且后续新增异常类型时容易出现漏处理的问题。
原有实现的问题
原有Controller Advice代码
@ExceptionHandler(ConversionFailedException.class) public ResponseEntity<ErrorResponse> handleConversionFailedException(final ConversionFailedException e) { return buildResponseEntity(HttpStatus.BAD_REQUEST, e); } @ExceptionHandler(value = {ActionNotFoundException.class}) public ResponseEntity<ErrorResponse> handleActionNotFoundException(ActionNotFoundException e) { return buildResponseEntity(HttpStatus.NOT_FOUND, e); } // 后续新增的异常处理逻辑 @ExceptionHandler(value = {NewRuntimeException.class}) public ResponseEntity<ErrorResponse> handleNewRuntimeException(NewRuntimeException e) { return buildResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, e); }
原有批量API异常处理代码
try { // 子请求调用逻辑 }catch(ConversionFailedException e){ return buildResponseEntity(HttpStatus.BAD_REQUEST, e); }catch(ActionNotFoundException e){ return buildResponseEntity(HttpStatus.NOT_FOUND, e); } // 此处遗漏了NewRuntimeException的处理逻辑
该实现的问题为:当@ControllerAdvice新增NewRuntimeException的处理逻辑时,批量API的catch块很容易遗漏对应异常的处理,导致返回结果和真实接口调用不一致。
当前临时方案
调整后的Controller Advice
@ExceptionHandler(Exception.class) public ResponseEntity<String> handleAllExceptions(final Exception e) { return ExceptionHandlerUtil.funcA(e); }
新增ExceptionHandlerUtil工具类
private ResponseEntity<ErrorResponse> funcA(Exception e) { if (e instanceof ConversionFailedException) { return buildResponseEntity(HttpStatus.BAD_REQUEST, e); } else if (e instanceof ActionNotFoundException) { return buildResponseEntity(HttpStatus.NOT_FOUND, e); } // 后续新增异常类型统一在此处添加,两处调用逻辑均可复用处理能力 }
调整后的批量API异常处理代码
try { // 子请求调用逻辑 }catch(Exception e){ return ExceptionHandlerUtil.funcA(e); }
该方案虽然解决了代码重复问题,但需要将原有分散的@ExceptionHandler方法全部移除,统一走工具类做类型判断,期望找到更优雅的原生方案,直接复用@ControllerAdvice的异常处理能力。
内容的提问来源于stack exchange,提问作者Saif

