背景
2个服务:A-common 和 BService,各自有异常处理器。
其中A中定义了通用的异常处理器,供所有服务直接调用。
但是B服务由于业务需求需要处理一些A中没有的异常,由于A中存在兜底逻辑:对Exception进行捕获,这个时候就要指定异常处理器的执行顺序。
解决方案
Spring的异常处理器是根据异常处理器被加载的顺序来顺序执行,比如:A->B->C ,如果B拦截并且处理了某个异常,就会直接抛出,C的异常处理器就执行不到了。
可以通过 @Order 注解来指定实体Bean被加载到Spring容器的顺序,注解中的值越小越优先加载。多个自定义的ExceptionHandler类的执行顺序就是被Spring加载到容器中Bean加载顺序,ExceptionHandlerMethodResolver根据order值进行执行。
原理:https://juejin.cn/post/6844903865054150669
代码
B的启动类
@Slf4j
@EnableSwagger2
@RegisterHttpService
@SpringBootApplication(scanBasePackages = {"com.bytedance.cg.gcrm","com.bytedance.cg.mtm.tenant.sdk"})
@MapperScan(basePackages = {
// 扫描ACommon的包,将其中的Spring组件给加载到B的Spring容器中
"com.Acommon.infrastructure",
"com.BService",
})
@EnableAsync
public class Application {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("GMT+0"));
ConvertPatternLayout.init();
log.info("start spring...");
SpringApplication.run(Application.class, args);
}
指定B的ExceptionHandler为第一执行顺序
@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)
public class GlobalExceptionHandlerFirst {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerFirst.class);
@ExceptionHandler({ThriftInvokeException.class})
@ResponseBody
public Response handleThriftInvokeException(ThriftInvokeException e) {
log.error("handle ThriftInvokeException. message:{}", new Object[]{e.getMessage()});
……dosth
}
}
参考
@Order的源码以及使用范例:https://blog.csdn.net/yaomingyang/article/details/86649072
1, 注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,Bean的加载顺序不受@Order或Ordered接口的影响
2, 加载代码的底层要支持优先级执行程序,否则即使配置上Ordered、@Order也是不起任何作用的
ExceptionHandlerMethodResolver调用链:https://juejin.cn/post/6844903865054150669