下面我会详细讲解“dubbo自定义异常的完整步骤与测试”的完整攻略:
规划异常类包结构
首先应该规划好异常类的包结构。通常情况下,我们会把异常类放在com.xxx.exception
包中,这个包可以在provider、consumer、api中共用。在com.xxx.exception
包中,我们可以建立一些子包,如com.xxx.exception.common
表示一些通用的异常,如参数异常、权限异常等;com.xxx.exception.biz
表示将业务相关的异常分门别类管理。如:
com.xxx.exception.biz.order
: 订单相关的异常com.xxx.exception.biz.user
: 用户、操作员等相关的异常com.xxx.exception.biz.product
: 商品相关的异常com.xxx.exception.biz.account
: 账户相关的异常com.xxx.exception.biz.stock
: 库存相关的异常com.xxx.exception.biz.finance
: 财务相关的异常
当然,包的数量、命名根据实际情况而定。可以参考阿里巴巴的开发规范。
编写异常类
规划好包结构以后,我们就可以开始编写自定义的异常类了。首先我们要确定一下需要自定义的异常类型。
通常情况下,我们自定义的异常应该继承自运行时异常RuntimeException
,因为它是编写业务逻辑时,最常用的异常类型。如果一个异常不需要在调用方法中被处理,那么就可以将它定义为运行时异常!
比如我们定义一个用户不存在异常类UserNotFoundException
package com.xxx.exception.biz.user;
public class UserNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public UserNotFoundException() {
super("user not found");
}
}
如上所示,当我们在调用过程中如果发现需要抛出用户不存在异常时,就可以抛出UserNotFoundException
了。如果需要指定异常信息,我们可以通过传参的方式进行。
如果我们的异常类型复杂些,需要包含更多信息,那么就可以自定义一个异常信息对象,如:
package com.xxx.exception.biz.order;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class OrderExceptionInfo {
private String errorCode;
private String errorMessage;
public OrderExceptionInfo(String errorCode, String errorMessage) {
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
}
然后我们就可以在异常类中引用这个异常信息对象了,如:
package com.xxx.exception.biz.order;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class OrderCreateException extends RuntimeException {
private static final long serialVersionUID = 1L;
private OrderExceptionInfo exceptionInfo;
public OrderCreateException(OrderExceptionInfo exceptionInfo) {
this.exceptionInfo = exceptionInfo;
}
}
使用自定义异常
在dubbo服务接口中,通常情况下我们不会定义具体的异常信息,而是直接抛出自定义的异常类(已经定义好了的异常类型)
比如:
package com.xxx.api.order;
public interface OrderService {
// 创建订单
Long createOrder(OrderDTO orderDTO) throws OrderCreateException;
// 取消订单
void cancelOrder(Long orderId) throws OrderCancelException;
// 查询订单
OrderDTO getOrder(Long orderId) throws OrderNotFoundException;
}
其中,涉及到3个自定义的异常类型:
OrderCreateException
: 订单创建异常,可能是参数错误、重复提交等原因OrderCancelException
: 订单取消异常,可能是非法操作等原因OrderNotFoundException
: 订单不存在异常,查询不到指定订单
接口实现类中,我们可以按照业务规则进行异常的抛出。
异常兜底
如果我们在抛出异常时,考虑到rpc调用过程中,网络传输等原因,抛出的异常类型可能不是我们预期的类型,这个时候就需要在服务消费方(Consumer)进行异常的处理。
比如:
@Reference(version = "1.0.0")
OrderService orderService;
public Long createOrder(OrderDTO orderDTO) {
try {
return orderService.createOrder(orderDTO);
} catch (OrderCreateException e) {
// 处理自定义异常
log.error(e.getMessage());
throw new BizException("订单创建失败", e.getCause());
} catch (Exception e) {
// 异常兜底
log.error("订单创建失败, 参数: {}", orderDTO, e);
throw new BizException("订单创建失败", e.getCause());
}
}
如上所示,在捕获自定义异常以外的错误情况中,我们可以通过日志打印出来,记录下请求参数,方便后续排查问题。
测试自定义异常
最后,我们需要对自定义异常进行测试。
@Reference(version = "1.0.0")
OrderService orderService;
@Test(expected = OrderNotFoundException.class)
public void testGetOrder() {
OrderDTO order = orderService.getOrder(1L);
}
如上所示,在测试中我们使用了@Test(expected)
注解来捕获异常,如果我们抛出的异常类型和expected
属性指定的异常类型一致,就算测试通过。
除了这种方法,还可以使用junit5中的assertThrows
方法来进行测试,比较麻烦些。
@Test
public void testGetOrder() {
Exception exception = assertThrows(OrderNotFoundException.class, () -> {
OrderDTO order = orderService.getOrder(1L);
});
String expectedMessage = "order not found";
String actualMessage = exception.getMessage();
assertTrue(actualMessage.contains(expectedMessage));
}
整个自定义异常的开发到测试流程就介绍完了。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:dubbo自定义异常的完整步骤与测试 - Python技术站