大家都知道,大部分企业都会有自己的自定义异常。
在某种特殊情况下,dubbo会将自定义异常转换为RuntimeException,例如:
我在dubbo-provider-service-impl里自定义一个异常TestException
public class TestException extends RuntimeException{
private static final long serialVersionUID = 2663095676298579664L;
private String message;
public TestException() {
}
public TestException(Exception e) {
super(e.getMessage(), e instanceof TestException ? (TestException)e : e);
this.message = e.getMessage();
}
public TestException(TestException te) {
super(te.getMessage(),te);
this.message = te.getMessage();
}
public TestException(String msg){
super(msg);
this.message = msg;
}
public String getMessage(){
String result;
if(this.message == null || "".equals(this.message)){
result = super.getMessage();
}else{
result = this.message;
}
return result;
}
}
接着,在dubbo-provider-service里定义TestService
public interface TestService {
public void test();
}
然后在dubbo-provider-service-impl中定义TestServiceImpl
@Service("testService")
public class TestServiceImpl implements TestService{
@Override
public void test() {
throw new TestException("this is TestException...");
}
}
创建一个dubbo消费者工程
注:dubbo中Testservice相关的配置省略
在dubbo-consumer中新建TestController
@RestController
@RequestMapping("/test")
public class TestController {
@Resource(name = "testService")
private TestService testService;
@RequestMapping("/test")
public String test() {
try {
testService.test();
} catch (Exception e) {
System.out.println(">>>>>>>>>>" + e.getClass());
e.printStackTrace();
}
return "SUCCESS";
}
}
启动这两个工程,访问dubbo-consumer中TestController的test方法,你就会发现控制台打印如下信息
注意,控制台中打印了“>>>>>>>>>>class java.lang.RuntimeException”
明明生产者中抛出的异常类型是TestException,怎么到了消费者中变成了RuntimeException呢
别急,我们先找下错误信息,往下拉,你会发现
就是这里对自定义异常进行了转换
就是这个invoke方法,我们来看一下它的注释
1.“directly throw if it's checked exception”:意思就是说,如果该异常是检查型异常,则直接抛出
2.“directly throw if the exception appears in the signature”:大概意思是,如果接口的方法声明中抛出了该异常,则直接抛出
3.“for the exception not found in method's signature, print ERROR message in server's log”:意思是,如果接口的方法中没有声明该异常,则打印ERROR日志
4.“directly throw if exception class and interface class are in the same jar file”:大概意思是:如果异常类和接口类在同一个jar中,则直接抛出
5.“directly throw if it's JDK exception”:意思是,如果是JDK中的异常,则直接抛出
6.“directly throw if it's dubbo exception”:如果是dubbo的异常,则直接抛出
7.“otherwise, wrap with RuntimeException and throw back to the client”:否则,包装成RuntimeException抛出给客户端
根据错误信息同时结合注释,我们知道是走了7,你可能会觉得很坑,但仔细想一下,他这样做是很有必要的,因为走了第七步说明生产者定义的异常类在消费者上是找不到的,这时如果不把它包装成RuntimeException,那么在反序列化时就会出现问题,会无法序列化。
所以,最好的办法是:将异常类定义在公共的jar包中,然后生产者和消费者都引用它,同时生产者的接口声明中抛出该异常。