快捷搜索:  汽车  科技

dubbo header 设置自定义值(正确透传自定义异常)

dubbo header 设置自定义值(正确透传自定义异常)@Activate(group = CommonConstants.PROVIDER) public class DubboExceptionFilter extends ListenableFilter { public DubboExceptionFilter() { super.listener = new ExceptionListener(); } @Override public Result invoke(Invoker<?> invoker Invocation invocation) throws RpcException { return invoker.invoke(invocation); } static class ExceptionListener implem

目录
  • 问题现象
  • 问题原因
  • 解决方案
  • 验证
问题现象

我们项目是通过Dubbo框架来进行服务注册和发现的,Service层抛出自定义BaseException异常,而在Controller层捕获到的竟然是RuntimeException异常,不符合预期。

dubbo header 设置自定义值(正确透传自定义异常)(1)

问题原因

想要知道问题出在什么地,只能了解dubbo是怎么处理异常的了。dubbo异常处理由filter链中org.apache.dubbo.rpc.filter.ExceptionFilter来处理的,咱们直接看源码吧。

@Activate(group = CommonConstants.PROVIDER) public class ExceptionFilter extends ListenableFilter { public exceptionFilter() { super.listener = new ExceptionListener(); } @Override public Result invoke(Invoker<?> invoker Invocation invocation) throws RpcException { return invoker.invoke(invocation); } static class ExceptionListener implements Listener { private Logger logger = LoggerFactory.getLogger(ExceptionListener.class); @Override public void onResponse(Result appResponse Invoker<?> invoker Invocation invocation) { // GenericService接口的实现类发生了异常,直接抛出 if (appResponse.hasException() && GenericService.class != invoker.getInterface()) { try { Throwable exception = appResponse.getException(); // 检查型异常,直接抛出 if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) { return; } // 方法签名上异常,直接抛出 try { Method method = invoker.getInterface().getMethod(invocation.getMethodName() invocation.getParameterTypes()); Class<?>[] exceptionClassses = method.getExceptionTypes(); for (Class<?> exceptionClass : exceptionClassses) { if (exception.getClass().equals(exceptionClass)) { return; } } } catch (NoSuchMethodException e) { return; } // for the exception not found in method's signature print ERROR message in server's log. 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)) { return; } // jdk异常,直接抛出 String className = exception.getClass().getName(); if (className.startsWith("java.") || className.startsWith("javax.")) { return; } // dubbo自定义异常RpcException,直接抛出 if (exception instanceof RpcException) { return; } // 其他异常都会被包装成RuntimeException异常抛出 appResponse.setException(new RuntimeException(StringUtils.toString(exception))); return; } catch (Throwable e) { logger.warn("Fail to ExceptionFilter when called by " RpcContext.getContext().getRemoteHost() ". service: " invoker.getInterface().getName() " method: " invocation.getMethodName() " exception: " e.getClass().getName() ": " e.getMessage() e); return; } } } ...... } }

再梳理下异常处理逻辑,抛出的异常都会被包装成RuntimeException异常处理,除了以下6种情况:

  • GenericService接口的实现类
  • 检查型异常(除RuntimeException和Error以及子类以外的异常)
  • 方法签名上异常(public void method() throws 任意异常)
  • 自定义异常类和接口类在同一个jar包
  • jdk异常(异常类以java./javax.开头的)
  • RpcException异常 那我们自定义BaseException异常属于以上6种情况吗?肯定不属于啊,所以被包裹成RuntimeException异常处理了,我们该如何处理下达到我们的预期?
解决方案

重写dubbo的ExceptionFilter,我这在原来基础上简单处理了下,大家可根据自己项目实际情况处理,代码如下:

@Activate(group = CommonConstants.PROVIDER) public class DubboExceptionFilter extends ListenableFilter { public DubboExceptionFilter() { super.listener = new ExceptionListener(); } @Override public Result invoke(Invoker<?> invoker Invocation invocation) throws RpcException { return invoker.invoke(invocation); } static class ExceptionListener implements Listener { private Logger logger = LoggerFactory.getLogger(ExceptionListener.class); @Override public void onResponse(Result appResponse Invoker<?> invoker Invocation invocation) { if (appResponse.hasException() && GenericService.class != invoker.getInterface()) { try { Throwable exception = appResponse.getException(); // 自定义BaseException异常,直接抛出 if (exception instanceof BaseException) { return; } //源码...... } //源码...... } }

配置如下:

  • 删除dubbo自带异常处理ExceptionFilter:dubbo.provider.filter:-exception
  • 添加自定义异常处理Filter:在META-INF/dubbo/com.alibaba.dubbo.rpc.Filter文件中,添加dubboExceptionFilter=类路径.DubboExceptionFilter
验证

调整后,再次跑下,符合预期。

dubbo header 设置自定义值(正确透传自定义异常)(2)



猜您喜欢: