在设计异常处理的框架时,需要考虑以下几点:
- 向客户端提供格式统一的异常返回
- 异常信息中应该包含足够多的上下文信息,最好是结构化的数据以便于客户端解析
- 不同类型的异常应该包含唯一标识,以便客户端精确识别
异常处理通常有两种形式,一种是层级式的,即每种具体的异常都对应了一个异常类,这些类最终继承自某个父异常;另一种是单一式的,即整个程序中只有一个异常类,再以一个字段来区分不同的异常场景。层级式异常的好处是能够显式化异常含义,但是如果层级设计不好可能导致整个程序中充斥着大量的异常类;单一式的好处是简单,而其缺点在于表意性不够。
本文的示例项目使用了层级式异常,所有异常都继承自一个AppException:
- public abstract class AppException extends RuntimeException {
- private final ErrorCode code;
- private final Map<String, Object> data = newHashMap();
- }
这里,ErrorCode枚举中包含了异常的唯一标识、HTTP状态码以及错误信息;而data字段表示各个异常的上下文信息。
在示例系统中,在没有找到订单时抛出异常:
- public class OrderNotFoundException extends AppException {
- public OrderNotFoundException(OrderId orderId) {
- super(ErrorCode.ORDER_NOT_FOUND, ImmutableMap.of("orderId", orderId.toString()));
- }
- }
在返回异常给客户端时,通过一个ErrorDetail类来统一异常格式:
- public final class ErrorDetail {
- private final ErrorCode code;
- private final int status;
- private final String message;
- private final String path;
- private final Instant timestamp;
- private final Map<String, Object> data = newHashMap();
- }
最终返回客户端的数据为:
- {
- requestId: "d008ef46bb4f4cf19c9081ad50df33bd",
- error: {
- code: "ORDER_NOT_FOUND",
- status: 404,
- message: "没有找到订单",
- path: "/order",
- timestamp: 1555031270087,
- data: {
- orderId: "123456789"
- }
- }
- }
可以看到,ORDER_NOT_FOUND与data中的数据结构是一一对应的,也即对于客户端来讲,如果发现了ORDER_NOT_FOUND,那么便可确定data中一定存在orderId字段,进而完成精确的结构化解析。
后台任务与分布式锁
除了即时完成客户端的请求外,系统中通常会有一些定时性的例行任务,比如定期地向用户发送邮件或者运行数据报表等;另外,有时从设计上我们会对请求进行异步化处理。此时,我们需要搭建后台任务相关基础设施。Spring原生提供了任务处理(TaskExecutor)和任务计划(TaskSchedulor)机制;而在分布式场景下,还需要引入分布式锁来解决并发冲突,为此我们引入一个轻量级的分布式锁框架ShedLock。
启用Spring任务配置如下:
- @Configuration
- @EnableAsync
- @EnableScheduling
- public class SchedulingConfiguration implements SchedulingConfigurer {
-
- @Override
- public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
- taskRegistrar.setScheduler(newScheduledThreadPool(10));
- }
-
- @Bean(destroyMethod = "shutdown")
- @Primary
- public TaskExecutor taskExecutor() {
- ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
- executor.setCorePoolSize(2);
- executor.setMaxPoolSize(5);
- executor.setQueueCapacity(10);
- executor.setTaskDecorator(new LogbackMdcTaskDecorator());
- executor.initialize();
- return executor;
- }
-
- }
(编辑:ASP站长网)
|