服务异常返回的设计
服务异常返回的设计
服务是不能抛出异常的(在《服务返回对象的设计》中有讨论这个问题)。
为了实现这个目的,在Java实现中,我们通常会用try-catch-finally语句包含整个方法体。
这样做是不优美的。
优美的程序应该是简洁的,只专注于做一件事(这里指不考虑异常处理),无重复代码的。
使用AOP处理服务方法抛出的异常
解决上面问题的一种思路是:引入一个服务方法注解和一个服务异常处理Aspect。
Aspect拦截服务方法,处理服务方法抛出的异常,并返回一个code为“ERROR”的服务返回对象。
服务方法注解ServiceMethod
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ServiceMethod {}
服务异常处理ServiceExcHandlerAspect
需要依赖aspectjrt
public class ServiceExcHandlerAspect {
public Object doAroundMethod(ProceedingJoinPoint point) {
Object response = null;
try {
response = point.proceed();
} catch (Throwable e) {
ServiceResponse<Serializable> err = new ServiceResponse<Serializable>();
err.setCode(ServiceCode.ERROR);
response = err;
}
return response;
}
}
Spring配置
略
细粒度的异常码
服务应该根据不同的服务,返回不同的异常码。
如果一个服务方法在发生异常时,一概返回ERROR异常码,未免太粗暴。
改进思路是引入服务异常类,这个异常类包含一个code字段。
当Aspect处理这类异常时,会根据这个异常的code字段,创建服务返回对象。
服务异常类
public class ServiceException extends RuntimeException {
private String code;
public String getCode() {
return code;
}
// 异常构造器
...
}
改进后的ServiceExcHandlerAspect
public class ServiceExcHandlerAspect {
public Object doAroundMethod(ProceedingJoinPoint point) {
Object response = null;
try {
response = point.proceed();
} catch (ServiceException e) {
response = exceptionResponse(e.getCode());
} catch (Throwable e) {
response = exceptionResponse(ServiceCode.ERROR);
}
return response;
}
private Object exceptionResponse(String code) {
ServiceResponse<Serializable> err = new ServiceResponse<Serializable>();
err.setCode(code);
return err;
}
}
另一种方案: 不使用AOP的传统方法
如果你不喜欢使用AOP, 你可以
public class ArticleListServiceImpl implements ArticleListService {
ServiceResponse<ListArticleData> listArticle(ListArticleRequest request) {
ServiceResponse<ListArticleData> response = null;
try {
response = doListArticle(request);
} catch (ServiceException e) {
response = exceptionResponse(e.getCode());
} catch (Throwable e) {
response = exceptionResponse(ServiceCode.ERROR);
}
return response;
}
ServiceResponse<ListArticleData> doListArticle(ListArticleRequest request) {
...
}
...
}