preface

When I was 17 years old, I wrote a series of Dubbo source code analysis based on the interview questions because I couldn’t control the impulse (of course, some fans also asked me to update the impulse again recently). At present, most of the fans of the public number are the previous fans, but here more introduction.

According to my interview experience, can write on the resume principle, source code and other keywords, is very have the core competitiveness. Last week and a public account fans exchange interview situation is as follows

Interview, the source of a wave of analysis, so that the interviewer tiger body a shock! After a bit of foreplay and what was expected to be nothing more than a physical convulsion, the interviewer says something that reverses the plot

“You are familiar with Dubbo source code, so do you have any problems when using it?”

I wipe, have no preparation of his, chrysanthemum suddenly a tight! At this point, we will face the situation of 50K and 5K if we fail to bluff, we will panic!

On how to counter-kill

I believe we have encountered similar problems in the interview, because there are many source code analysis online, a lot of people “surprise” before the exam, but encounter like to ask details of the interviewer, eventually escape from the law, there is no escape. Faced with this problem, how do we counter-kill a wave? Then I will start from a chat record, after all, only pay attention to the public number, have a real scene of the source code combat (very important), encounter this kind of problem, just do not appear tiger tears

Actual Scene Description

So let’s remove the business correlation and extract a minimalist model. In our company, we usually have our own custom exception, and then this custom exception is put in common.jar for other module dependencies, for example, I define a HelloException here

public class HelloException extends RuntimeException {

    public HelloException(a) {}public HelloException(String message) {
        super(message); }}Copy the code

Then let’s write the simplest possible demo of Dubbo, as follows

interface

public interface DemoService {

    String sayHello(String name);

}
Copy the code

provider

public class DemoServiceImpl implements DemoService {

    public String sayHello(String name) {
        throw new HelloException("Official Account: Fat Chao"); }}Copy the code

consumer

public class DemoAction {

    private DemoService demoService;

    public void setDemoService(DemoService demoService) {
        this.demoService = demoService;
    }

    public void start(a) throws Exception {
        try {
            String hello = demoService.sayHello("Official Account: Fat Chao");
        } catch (HelloException helloException) {
            System.out.println("Catch helloException here"); }}}Copy the code

As described in the chat, the Consumer calls The Provider, which throws a HelloException. However, the consumer catches a different HelloException.

So let’s run it

As the colleague said. Why is that? Before not seen the fat toward Dubbo source code analysis series of students this time tend to use the most inefficient solution, the abnormal stack to the wechat group a throw, all kinds of help. But often have no harvest, and then sigh why the society is so indifferent!

But I believe that the public number of old fans have mastered the skills of reading source code, and fat toward the same sitting bosom not disorderly, nine shallow a deep straight into the source code. Let’s first look at the exception stack

Unless masturbation much see not clear (suggest to quit masturbation), otherwise this line is abnormal and fat face same, like the firefly in inky, so bright, so outstanding

com.alibaba.dubbo.rpc.filter.ExceptionFilter.invoke(ExceptionFilter.java:108)
Copy the code

So let’s find out

    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
                    if (! (exception instanceof RuntimeException) && (exception instanceof Exception)) {
                        return result;
                    }
                    // There is a declaration on the method signature, which 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)) {
                                returnresult; }}}catch (NoSuchMethodException e) {
                        return result;
                    }

                    // ERROR logs are printed on the server side for exceptions not defined on the method signature
                    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);

                    // The exception class and the interface class are in the same JAR package, directly thrown
                    String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
                    String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
                    if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)){
                        return result;
                    }
                    // is a JDK exception thrown directly
                    String className = exception.getClass().getName();
                    if (className.startsWith("java.") || className.startsWith("javax.")) {
                        return result;
                    }
                    // Is an exception of Dubbo itself, thrown directly
                    if (exception instanceof RpcException) {
                        return result;
                    }

                    // Otherwise, wrap it as 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);
                    returnresult; }}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);
            throwe; }}Copy the code

Reading the source code on the phone may not be friendly, but it doesn’t matter, it has perfect Chinese annotations, he wanted to express the following:

1. If the checked exception is checked, throw it. Obviously, our HelloException is RuntimeException and does not fit

2. Throw a declaration in the method signature. Obviously, our interface did not declare this exception

3. Exception classes and interface classes are in the same JAR package and are directly thrown. Obviously, our exception class is in common.jar and the interface is in api.jar

4. JDK built-in exception, directly thrown. Obviously, this HelloException is our custom and does not fit

5. RpcException is a Dubbo exception. Obviously, this HelloException is our own and has almost nothing to do with RpcException.

6. Otherwise, wrap it as RuntimeException and throw it to the client. Because none of the above is met, this exception is thrown wrapped as a RuntimeException (important)

CatchHelloException is not a catch because it is wrapped as RuntimeException

Why did Dubbo do this

Maybe you look at this and think that’s a bad judgment. Why did Dubbo do this? We look at the source code, the most important thing is to know why the author so designed, only to know why so designed is through the depth of thinking, otherwise look at the climax, look after forget. Explain why this design, is also an important reason for everyone to pay attention to the fat public number.

In fact, Dubbo’s consideration was based on serialization. If you think about it, if the provider throws an exception that is defined only by the provider, then the exception reaches the consumer and obviously cannot be serialized. So you pay attention to Dubbo’s judgment. Let’s take a look at his judgment

1. Checked and RuntimeExceptions are of different types. Forcibly wrapping them may cause conversion errors, so throw them instead

2. Declaration on method signature. The method signature is declared if the exception is defined in provider.jar, because consumer depends on api.jar, not provider.jar. However, if the compile succeeds, the consumer can rely on this exception, so serialization is not a problem

Both provider and consumer rely on the API. If the exception is in the API, then the serialization is fine

Both provider and consumer rely on the JDK, so serialization is not a problem

Both provider and consumer rely on Dubbo, and the serialization of Dubbo is not a problem

6. Otherwise, wrap it as RuntimeException and throw it to the client. In this case, it is possible that the exception is provider.jar custom, so the provider will serialize it when it throws it, and since the consumer does not rely on provider.jar, it cannot deserialize the exception when it reaches the consumer. The exception is wrapped as a RuntimeException, which is a class in the JDK and can be serialized anywhere.

How to solve

Now that we know how this works, it’s easy to solve. Let me just list some examples, such as the specification that requires the business side interface to declare HelloException

Write in the last

Of course, fat toward the interview, also have been asked similar questions, you have encountered with XXX pit. “Said the interviewer, under a wave of aggressive analysis

“You are so handsome.”

Fat smiled a knowing smile

Instead he said

“You look better when you smile!”


Fertilizer toward is a focus on principle, source code, development skills of technical public number, number of original thematic source code analysis, real scene source code principle combat (key).Scan the following QR codePay attention to fat, let should build rocket you, no longer screw!