1、抛出问题
dubbo在Provider端抛出自定义异常的时候会自动转换成RunTimeException异常自定义异常tostring放在RunTimeException的msg中,导致我们在调用的时候不能正确获取到我们想要的异常或者信息。
2、原因分析
Dubbo异常处理类ExceptionFilter
@Activate(
group = {"provider"}
)
public class ExceptionFilter implements Filter {
private final Logger logger;
public ExceptionFilter() {
this(LoggerFactory.getLogger(ExceptionFilter.class));
}
public ExceptionFilter(Logger logger) {
this.logger = logger;
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
Result result = invoker.invoke(invocation);
if (result.hasException() && GenericService.class != invoker.getInterface()) {
try {
Throwable exception = result.getException();
// 如果是checked异常,直接抛出
if (!(exception instanceof RuntimeException) && exception instanceof Exception) {
return result;
} else {
try {
// 在方法签名上有声明,返回
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
Class<?>[] exceptionClassses = method.getExceptionTypes();
Class[] arr$ = exceptionClassses;
int len$ = exceptionClassses.length;
for(int i$ = 0; i$ < len$; ++i$) {
Class<?> exceptionClass = arr$[i$];
if (exception.getClass().equals(exceptionClass)) {
return result;
}
}
} catch (NoSuchMethodException var11) {
return result;
}
this.logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);
// 异常类和接口类在同一jar包里,返回
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
if (serviceFile != null && exceptionFile != null && !serviceFile.equals(exceptionFile)) {
String className = exception.getClass().getName();
// 如果是是JDK自带的异常,返回
if (!className.startsWith("java.") && !className.startsWith("javax.")) {
//把异常转换成RuntimeException返回
return (Result)(exception instanceof RpcException ? result : new RpcResult(new RuntimeException(StringUtils.toString(exception))));
} else {
return result;
}
} else {
return result;
}
}
} catch (Throwable var12) {
this.logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + var12.getClass().getName() + ": " + var12.getMessage(), var12);
return result;
}
} else {
return result;
}
} catch (RuntimeException var13) {
this.logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + var13.getClass().getName() + ": " + var13.getMessage(), var13);
throw var13;
}
}
}
3、解决办法
所以能直接抛出的异常有:
1、实现了GenericService接口
2、checked异常
3、在方法签名上有声明
4、异常类和接口类在同一jar包里
5、JDK自带的异常
6、是Dubbo本身的异常
解决办法二:自定义dubbo的异常filter
从ExtensionLoader类中可以发现,spi加载的目录可以看到
按照dubbo的目录创建Filter。建议直接把dubbo源码中的copy过来。目录结构
把Filter中的内容替换成我们自定义的Filter路径:exception=com.gaol.test.config.DubboExceptionFilter
exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter
自定义Filter
@Log4j2
@Activate(group = {"provider"})
public class DubboExceptionFilter implements Filter {
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
Result result = invoker.invoke(invocation);
if (result.hasException() && GenericService.class != invoker.getInterface()) {
try {
Throwable exception = result.getException();
if (!(exception instanceof RuntimeException) && exception instanceof Exception) {
return result;
} else {
try {
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
Class<?>[] exceptionClassses = method.getExceptionTypes();
Class[] arr$ = exceptionClassses;
int len$ = exceptionClassses.length;
for(int i$ = 0; i$ < len$; ++i$) {
Class<?> exceptionClass = arr$[i$];
if (exception.getClass().equals(exceptionClass)) {
return result;
}
}
} catch (NoSuchMethodException var11) {
return result;
}
log.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
if (serviceFile != null && exceptionFile != null && !serviceFile.equals(exceptionFile)) {
String className = exception.getClass().getName();
//如果是我们系统自定义异常直接返回
if(className.startsWith("com.gaol.test.exception")){
return result;
}
if (!className.startsWith("java.") && !className.startsWith("javax.")) {
return (Result)(exception instanceof RpcException ? result : new RpcResult(new RuntimeException(StringUtils.toString(exception))));
} else {
return result;
}
} else {
return result;
}
}
} catch (Throwable var12) {
log.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + var12.getClass().getName() + ": " + var12.getMessage(), var12);
return result;
}
} else {
return result;
}
} catch (RuntimeException var13) {
log.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + var13.getClass().getName() + ": " + var13.getMessage(), var13);
throw var13;
}
}
}
共同进步!!!!!!!!!