Reprinted: http://blog.csdn.net/xlee1905/article/details/44660449
When dubbo's service end defines a custom exception to throw, it finds that it cannot be instanceof in the Controller, and the self-defined exception class is converted into a Runtime exception. Dubbo source code:
[java] view plain copy
- 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 it is a checked exception, throw it directly
- if (! (exception instanceof RuntimeException) && (exception instanceof Exception)) {
- return result;
- }
- // There is a statement in the method signature, and it is thrown directly
- try {
- Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
- Class<?>[] exceptionClassses = method.getExceptionTypes();
- for (Class<?> exceptionClass : exceptionClassses) {
- if (exception.getClass().equals(exceptionClass)) {
- return result;
- }
- }
- } catch (NoSuchMethodException e) {
- return result;
- }
- // For exceptions not defined on the method signature, print the ERROR log on the server side
- 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);
- // Exception class and interface class are in the same jar package, throw directly
- String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
- String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
- if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){
- return result;
- }
- // It is an exception that comes with JDK and is thrown directly
- String className = exception.getClass().getName();
- if (className.startsWith("java.") || className.startsWith("javax.")) {
- return result;
- }
- // It is an exception of Dubbo itself, directly thrown
- if (exception instanceof RpcException) {
- return result;
- }
- // Otherwise, wrap it into a RuntimeException and throw it to the client
- return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
- } 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 result;
- }
- }
- return result;
- } catch (RuntimeException e) {
- logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
- + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
- + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
- throw e;
- }
- }
Therefore, if you want to throw a custom exception on the service side of dubbo, you can only declare the exception to be thrown on the interface method of the service side, or package the exception class with the interface, or implement dubbo's GenericService in the implementation class of the interface interface.
The first option is not used, because it is more serious intrusion into the code.
The second solution can be realized, but for the current business framework, it is impossible to make the interface class and exception class the same package.
So in the end, I chose to let the interface implementation class implement the GenericService interface, but did not do any method body processing for the $invoke method that needs to be implemented, and discarded it directly.
Regarding the handling of custom exception classes on the service side of dubbo, some people don't understand why dubbo needs to convert the custom exception classes to Runtime exceptions instead of directly throwing the original exception type. Or is there a friend who knows more about dubbo and has a better way to deal with custom exceptions.
reference