Hi, everyone. I’m the Java class rep. Today we’re going to talk about Dubbo.

Recommendation: Dubbo, as a high-performance RPC framework, is widely used in micro-service architecture. Based on an exception handling in the development process, this paper deeply analyzes the exception handling logic of Dubbo and gives the best practice of Dubbo exception handling in combination with the source code.

1 background

In our daily business development process, we typically customize some business exceptions in order to make our business code more robust and to return friendlier prompts when we encounter errors. According to business needs, it can be divided into custom checked exceptions and non-checked exceptions

Review of knowledge points

The Exception class and its subclasses, except the subclasses of RuntimeException, are collectively called checked exceptions. If such exceptions are likely to be thrown during method execution, you must declare them on the method signature

The RuntimeException class and its subclasses, collectively known as unchecked exceptions. If such exceptions are likely to be thrown during method execution, you do not have to declare them on the method signature

The project that the class representative was in charge of was implemented with the micro-service of SpringCloudAlibaba. In the development, the brothers in the group encountered a problem: When Dubbo RPC is called, the provider throws a business class exception that is not checked. The consumer receives the RuntimeException and the message is spliced together with the stack information.

2 The problem recurs

In Dubbo micro-service, providers are divided into APIs and services, and consumers only need to introduce APIs to call service instances from the registry.

The exception is wrapped as a RuntimeException when a custom, unchecked exception is thrown in a Service and the corresponding API package does not have the exception class.

Dubbo is an RPC framework in which clients call remote methods and the parameters and return values are serialized and deserialized into byte arrays. The Consumer must recognize this exception in order to deserialize successfully.

Obviously, we threw the exception that Dubbo thought Consumer didn’t know and wrapped the exception in order to avoid deserialization failure.

Dubbo exception handling mechanism is described below in combination with the source code.

3 Source Code Analysis

ExceptionFilter class handles exceptions for the DUBBO remote call

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 checked, throw if (! (exception instanceof RuntimeException) && (exception instanceof Exception)) { return result; } // The method signature has a declaration, 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; } // Exception not defined on method signature, Logger. Error ("Got unchecked and undeclared exception which called by "+) prints the ERROR log on the server RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception); // ServiceFile = Reflectutils.getCodebase (Invoker.getInterface ()); // ServiceFile = Reflectutils.getInterface (); String exceptionFile = ReflectUtils.getCodeBase(exception.getClass()); if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){ return result; } // String ClassName = Exception.getClass ().getName(); if (className.startsWith("java.") || className.startsWith("javax.")) { return result; } if (Exception instanceof rpcException) {return result; } 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; }

As you can see from the source code, the main function of this class is to return exceptions thrown by the interface, which Dubbo defines as the following cases:

  1. If it ischeckedException, thrown directly
  2. There is a declaration on the method signature and it is thrown directly
  3. Anything that does not conform to 1,2 is considered an error, and an ERROR log is printed and the following processing is attempted:

    • The exception class is the same as the interface classjarIn the bag, just throw it out
    • isJDKThe built-in exception is thrown directly
    • isDubboThrow an exception of its own
    • Otherwise, pack asRuntimeExceptionThrow it to the client

In fact, Dubbo, as an RPC framework, has already taken into account all kinds of exception throwing situations. Finally, if Dubbo thinks the consumer doesn’t know the exception, it will wrap a RuntimeException to prevent deserialization failure.

If a consumer can’t find an exception thrown by a provider, put it bluntly-it’s the developer’s fault, and blaming Dubbo for that would be unfair!

4 Best Practices

Dubbo Website ->Dubbo 2.7-> User Documentation -> Servicalization Best Practices

The subcontract

It is recommended to put the service interface, service model, service exception, etc. into the API package, because the service model and exception are also part of the API, and this also conforms to the subcontracting principles: Reuse Publishing Equivalence (REP), Common Reuse (CRP).

Therefore, a Provider-API that follows Dubbo best practices should include a service interface package, a service model package, and a service exception package. All exceptions used in a service should be declared in the API package so that the consumer calls Dubbo:

The exception class is the same as the interface class
jarIn the bag, just throw it out

To avoid being wrapped in a RuntimeException and thrown to the client by Dubbo.

So, for the problem we encountered at the start of this article, we just need to define the unchecked exceptions thrown from the provider-service in the provider-API, and throw them on the corresponding method, which can prevent being wrapped by Dubbo. There is no DUBBO error because no exception is declared in the method signature. Also, because it is a non-checked exception, the client is not forced to try catch the method.

A reference to subcontracting practice:

+ - SCR | + - demo | + - domain (business domain to transmit data with DTO) | + - the service implementation class service interface (API) | + - the exception of custom exception (business domain)

5 detours

If you Google the keyword “Dubbo exception handling”, you’ll find almost all articles along these lines:

  1. Custom oneExceptionFilterDubboUse, compatible with their own business exception classes
  2. Write an AOP on the provider side to block all exceptions and handle them yourself
  3. theuncheckedAbnormal insteadcheckedabnormal

Of course, all of the above can solve the problem, but does it mean killing a chicken with a bull’s eye?

The underlying framework is to blame for code development that is not standardized and does not follow best practices. Dubbo is trying to be generic, but the above approach is making the code tightly coupled.

To summarize the essence of the problem: Dubbo wraps the exception in order to prevent deserialization failures when it thinks Consumer can’t find the exception class. In view of this essence, we use the simplest, most efficient, the least impact solution can be solved.

The rep believes that the reader, combined with the Dubbo exception handling source code, should be able to make their own judgments.

6 reflection

In most cases, we can find the answer to the problem we encounter. For the same problem, there may be a variety of solutions. What we need to do is to find the essence of the problem, draw inferences from one example, and choose the most appropriate solution according to the actual situation of our own business.

Never follow blindly. It is better to have no books than to believe them all.


Spring Validation is used to gracefully validate the downloaded attachment name of the parameter. Is it a total gibberish? Spring Validation is used to gracefully validate the downloaded attachment name. It’s time you read the RFC documentation! MySQL priority queue (order by limit problem)


Code word is not easy, welcome thumb up concern and share.

Search: 【The Java class representative], pay attention to the public number, a more daily, timely access to more Java dry goods.