学习笔记----Dubbo服务引用原理

401 阅读17分钟

Dubbo3.0 引用源码

前提:对应标注了@DubboReference生成的BeanDefinition是

{
    "decoratedDefinition": {
        "beanDefinition": {
            "beanClass": "interface org.apache.dubbo.springboot.demo.DemoService",
            "scope": "",
            "lazyInit": false,
            "autowireMode": 0,
            "dependencyCheck": 0,
            "autowireCandidate": true,
            "primary": false,
            "qualifiers": [],
            "nonPublicAccessAllowed": true,
            "lenientConstructorResolution": true,
            "constructorArgumentValues": {
                "indexedArgumentValues": {},
                "genericArgumentValues": []
            },
            "propertyValues": [],
            "methodOverrides": {
                "overrides": []
            },
            "enforceInitMethod": true,
            "enforceDestroyMethod": true,
            "synthetic": false,
            "role": 0
        },
        "beanName": "demoService_decorated"
    },
    "targetType": "class org.apache.dubbo.config.spring.ReferenceBean",
    "beanClass": "class org.apache.dubbo.config.spring.ReferenceBean",
    "scope": "singleton",
    "lazyInit": false,
    "autowireMode": 0,
    "dependencyCheck": 0,
    "autowireCandidate": true,
    "primary": false,
    "qualifiers": [],
    "nonPublicAccessAllowed": true,
    "lenientConstructorResolution": true,
    "constructorArgumentValues": {
        "indexedArgumentValues": {},
        "genericArgumentValues": []
    },
    "propertyValues": [
        {
            "name": "id",
            "value": "demoService",
            "optional": true,
            "converted": true,
            "convertedValue": "demoService"
        }
    ],
    "methodOverrides": {
        "overrides": []
    },
    "enforceInitMethod": true,
    "enforceDestroyMethod": true,
    "synthetic": false,
    "role": 0
}

可以看到beanClass是org.apache.dubbo.config.spring.ReferenceBean,而beanName的值是demoService

下面是构建“demoService”这个bean对象的时候的栈帧信息,

转存失败,建议直接上传图片文件

因为ReferenceBean本身是个FactoryBean所以会去调用它的getObject()方法,

转存失败,建议直接上传图片文件

进入createLazyProxy()方法,这个方法沿用了Spring的AOP的功能,使用AOP的ProxyFactoryTargetSource,dubbo使用了自定义的TargetSource ,是DubboReferenceLazyInitTargetSource。它什么时候使用的呢?先暂时放一放,知道有这么个东西。

先看看这个createLazyProxy()方法:

private void createLazyProxy() {

    //set proxy interfaces
    //see also: org.apache.dubbo.rpc.proxy.AbstractProxyFactory.getProxy(org.apache.dubbo.rpc.Invoker<T>, boolean)
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTargetSource(new DubboReferenceLazyInitTargetSource());
    proxyFactory.addInterface(interfaceClass);
    Class<?>[] internalInterfaces = AbstractProxyFactory.getInternalInterfaces();
    for (Class<?> anInterface : internalInterfaces) {
        proxyFactory.addInterface(anInterface);
    }
    if (!StringUtils.isEquals(interfaceClass.getName(), interfaceName)) {
        //add service interface
        try {
            Class<?> serviceInterface = ClassUtils.forName(interfaceName, beanClassLoader);
            proxyFactory.addInterface(serviceInterface);
        } catch (ClassNotFoundException e) {
            // generic call maybe without service interface class locally
        }
    }
    //看这里,走到org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)方法
    this.lazyProxy = proxyFactory.getProxy(this.beanClassLoader);
}

org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)方法

public Object getProxy(@Nullable ClassLoader classLoader) {
  //在dubbo中,createAopProxy()方法会返回org.springframework.aop.framework.JdkDynamicAopProxy对象,它也是JDK动态代理的
  //java.lang.reflect.InvocationHandler对象,
  //它里面org.springframework.aop.framework.JdkDynamicAopProxy#advised属性就是上面的proxyFactory对象。
  //调用到org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法
   return createAopProxy().getProxy(classLoader);
}

org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)方法

public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isTraceEnabled()) {
      logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
   }
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

这个方法的栈帧信息如下:

转存失败,建议直接上传图片文件

这里面就要调用到JDK动态代理的方法了,既然说到JDK动态代理,那就不得不说java.lang.reflect.InvocationHandler了,这里的动态代理对象的java.lang.reflect.InvocationHandler就是上面的org.springframework.aop.framework.JdkDynamicAopProxy

既然是动态代理的对象,肯定会动态生成Class对象,即这里的$Proxy63

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.concurrent.CompletableFuture;
import org.aopalliance.aop.Advice;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import org.apache.dubbo.springboot.demo.DemoService;
import org.springframework.aop.Advisor;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.AopConfigException;
import org.springframework.core.DecoratingProxy;

public final class $Proxy63 extends Proxy implements DemoService, EchoService, Destroyable, SpringProxy, Advised, DecoratingProxy {
    private static Method m1;
    private static Method m5;
    private static Method m14;
    private static Method m18;
    private static Method m11;
    private static Method m20;
    private static Method m8;
    private static Method m7;
    private static Method m27;
    private static Method m22;
    private static Method m23;
    private static Method m0;
    private static Method m9;
    private static Method m24;
    private static Method m13;
    private static Method m12;
    private static Method m3;
    private static Method m2;
    private static Method m29;
    private static Method m6;
    private static Method m17;
    private static Method m30;
    private static Method m19;
    private static Method m26;
    private static Method m28;
    private static Method m21;
    private static Method m15;
    private static Method m4;
    private static Method m25;
    private static Method m10;
    private static Method m16;

    public $Proxy63(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final Object $echo(Object var1) throws  {
        try {
            return (Object)super.h.invoke(this, m5, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean isExposeProxy() throws  {
        try {
            return (Boolean)super.h.invoke(this, m14, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void addAdvisor(Advisor var1) throws AopConfigException {
        try {
            super.h.invoke(this, m18, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean isProxyTargetClass() throws  {
        try {
            return (Boolean)super.h.invoke(this, m11, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void removeAdvisor(int var1) throws AopConfigException {
        try {
            super.h.invoke(this, m20, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final Class[] getProxiedInterfaces() throws  {
        try {
            return (Class[])super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final TargetSource getTargetSource() throws  {
        try {
            return (TargetSource)super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int indexOf(Advisor var1) throws  {
        try {
            return (Integer)super.h.invoke(this, m27, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void addAdvice(int var1, Advice var2) throws AopConfigException {
        try {
            super.h.invoke(this, m22, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void addAdvice(Advice var1) throws AopConfigException {
        try {
            super.h.invoke(this, m23, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean isInterfaceProxied(Class var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m9, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean removeAdvice(Advice var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m24, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void setExposeProxy(boolean var1) throws  {
        try {
            super.h.invoke(this, m13, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void setTargetSource(TargetSource var1) throws  {
        try {
            super.h.invoke(this, m12, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String sayHello(String var1) throws  {
        try {
            return (String)super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class getTargetClass() throws  {
        try {
            return (Class)super.h.invoke(this, m29, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void $destroy() throws  {
        try {
            super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void addAdvisor(int var1, Advisor var2) throws AopConfigException {
        try {
            super.h.invoke(this, m17, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final Class getDecoratedClass() throws  {
        try {
            return (Class)super.h.invoke(this, m30, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean removeAdvisor(Advisor var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m19, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int indexOf(Advice var1) throws  {
        try {
            return (Integer)super.h.invoke(this, m26, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean isFrozen() throws  {
        try {
            return (Boolean)super.h.invoke(this, m28, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean replaceAdvisor(Advisor var1, Advisor var2) throws AopConfigException {
        try {
            return (Boolean)super.h.invoke(this, m21, new Object[]{var1, var2});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void setPreFiltered(boolean var1) throws  {
        try {
            super.h.invoke(this, m15, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final CompletableFuture sayHelloAsync(String var1) throws  {
        try {
            return (CompletableFuture)super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toProxyConfigString() throws  {
        try {
            return (String)super.h.invoke(this, m25, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Advisor[] getAdvisors() throws  {
        try {
            return (Advisor[])super.h.invoke(this, m10, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final boolean isPreFiltered() throws  {
        try {
            return (Boolean)super.h.invoke(this, m16, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m5 = Class.forName("org.apache.dubbo.rpc.service.EchoService").getMethod("$echo", Class.forName("java.lang.Object"));
            m14 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isExposeProxy");
            m18 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Class.forName("org.springframework.aop.Advisor"));
            m11 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isProxyTargetClass");
            m20 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Integer.TYPE);
            m8 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getProxiedInterfaces");
            m7 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetSource");
            m27 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.springframework.aop.Advisor"));
            m22 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Integer.TYPE, Class.forName("org.aopalliance.aop.Advice"));
            m23 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvice", Class.forName("org.aopalliance.aop.Advice"));
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m9 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isInterfaceProxied", Class.forName("java.lang.Class"));
            m24 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvice", Class.forName("org.aopalliance.aop.Advice"));
            m13 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setExposeProxy", Boolean.TYPE);
            m12 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setTargetSource", Class.forName("org.springframework.aop.TargetSource"));
            m3 = Class.forName("org.apache.dubbo.springboot.demo.DemoService").getMethod("sayHello", Class.forName("java.lang.String"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m29 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getTargetClass");
            m6 = Class.forName("org.apache.dubbo.rpc.service.Destroyable").getMethod("$destroy");
            m17 = Class.forName("org.springframework.aop.framework.Advised").getMethod("addAdvisor", Integer.TYPE, Class.forName("org.springframework.aop.Advisor"));
            m30 = Class.forName("org.springframework.core.DecoratingProxy").getMethod("getDecoratedClass");
            m19 = Class.forName("org.springframework.aop.framework.Advised").getMethod("removeAdvisor", Class.forName("org.springframework.aop.Advisor"));
            m26 = Class.forName("org.springframework.aop.framework.Advised").getMethod("indexOf", Class.forName("org.aopalliance.aop.Advice"));
            m28 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isFrozen");
            m21 = Class.forName("org.springframework.aop.framework.Advised").getMethod("replaceAdvisor", Class.forName("org.springframework.aop.Advisor"), Class.forName("org.springframework.aop.Advisor"));
            m15 = Class.forName("org.springframework.aop.framework.Advised").getMethod("setPreFiltered", Boolean.TYPE);
            m4 = Class.forName("org.apache.dubbo.springboot.demo.DemoService").getMethod("sayHelloAsync", Class.forName("java.lang.String"));
            m25 = Class.forName("org.springframework.aop.framework.Advised").getMethod("toProxyConfigString");
            m10 = Class.forName("org.springframework.aop.framework.Advised").getMethod("getAdvisors");
            m16 = Class.forName("org.springframework.aop.framework.Advised").getMethod("isPreFiltered");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

因此返回的这个$Proxy63对象就是标注了@DubboReference注解的那个接口,在消费端所以对应的代理对象。它就是在Spring容器中,

beanName为“demoService”的对象。

它的栈帧信息如下:

转存失败,建议直接上传图片文件

上面的图里我们提到了,虽然客户端的实际的代理对象已经生成了,但是ref还是null,这个ref就是用来和服务端通信的,它是在哪里生成的呢?在org.apache.dubbo.config.deploy.DefaultModuleDeployer#referServices方法----->

org.apache.dubbo.config.ReferenceConfig#init方法里面去生成的,是DemoServiceDubboProxy0对象,也是个代理对象

转存失败,建议直接上传图片文件

转存失败,建议直接上传图片文件

这个ref里面就包含了所有的与服务端通信的Invoker对象,也就是包装了NettyClient的Invoker对象,至于ref是怎么生成的,见流程图www.processon.com/diagraming/…

那么到现在,消费端端整个代理对象已经完全的生成结束了,可以拿来用了。根据方法调用,来串一下整体的对象是怎么协作的,不然晕的一逼。

来调用一下:

@SpringBootApplication
@Service
@EnableDubbo
public class ConsumerApplication {

    @DubboReference(timeout = 100000)
    private DemoService demoService;

    public static void main(String[] args) {

        ConfigurableApplicationContext context = SpringApplication.run(ConsumerApplication.class, args);
        ConsumerApplication application = context.getBean(ConsumerApplication.class);
        String result = application.doSayHello("world");
        System.out.println("result: " + result);
    }

    public String doSayHello(String name) {
        return demoService.sayHello(name);
    }
}

转存失败,建议直接上传图片文件

代理对象嘛,当然是调用到它的java.lang.reflect.InvocationHandler#invoke方法,这里是org.springframework.aop.framework.JdkDynamicAopProxy#invoke方法。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;

   TargetSource targetSource = this.advised.targetSource;
   Object target = null;

   try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         // The target does not implement the equals(Object) method itself.
         return equals(args[0]);
      }
      else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         // The target does not implement the hashCode() method itself.
         return hashCode();
      }
      else if (method.getDeclaringClass() == DecoratingProxy.class) {
         // There is only getDecoratedClass() declared -> dispatch to proxy config.
         return AopProxyUtils.ultimateTargetClass(this.advised);
      }
      else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         // Service invocations on ProxyConfig with the proxy config...
         return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal;

      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }

      // Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
     //这个targetSource就是前面提了一嘴的DubboReferenceLazyInitTargetSource,就是在这里使用的,这就是
     //Spring AOP的用法,那么这个getTarget方法的作用是啥?见下面分析
     //getTarget方法获取的是什么呢?其实就是上面的ref对象,也就是DemoServiceDubboProxy0对象
      target = targetSource.getTarget();
      Class<?> targetClass = (target != null ? target.getClass() : null);

      // Get the interception chain for this method.
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
         // We can skip creating a MethodInvocation: just invoke the target directly
         // Note that the final invoker must be an InvokerInterceptor so we know it does
         // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
        //拿这个ref对象去进行服务端的调用,里面就涉及到了netty的通信了
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      }
      else {
         // We need to create a method invocation...
         MethodInvocation invocation =
               new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         // Proceed to the joinpoint through the interceptor chain.
         retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         // Special case: it returned "this" and the return type of the method
         // is type-compatible. Note that we can't help if the target sets
         // a reference to itself in another returned object.
         retVal = proxy;
      }
      else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
         throw new AopInvocationException(
               "Null return value from advice does not match primitive return type for: " + method);
      }
      return retVal;
   }
   finally {
      if (target != null && !targetSource.isStatic()) {
         // Must have come from TargetSource.
         targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

转存失败,建议直接上传图片文件

上面的getTarget方法最终会调用到org.apache.dubbo.config.spring.ReferenceBean.DubboReferenceLazyInitTargetSource#createObject方法,

//在第一次真正开始调用消费者的时候会走这个方法,把值赋给org.springframework.aop.target.AbstractLazyCreationTargetSource.lazyTarget属性
//
//org.apache.dubbo.config.spring.ReferenceBean.DubboReferenceLazyInitTargetSource#createObject------>
//org.apache.dubbo.config.spring.ReferenceBean#getCallProxy----->org.apache.dubbo.config.ReferenceConfig#get----
//---->去生成dubbo消费端的invoke。这个方法其实也就是去生成ref并赋值给ref的,
//其实呢这个时候其实已经生成了,org.apache.dubbo.config.ReferenceConfig#get方法在org.apache.dubbo.config.deploy.DefaultModuleDeployer#referServices方法中已经调用了,也就是已经生成了dubbo消费端的invoke也就是MigrationInvoker对象

@Override
protected Object createObject() throws Exception {
    System.out.println("ref创建开始"+Thread.currentThread());
    return getCallProxy();
}

看到这里,可以总结一下,Dubbo的消费端对象,主要是由两个代理对象构成,1个是$Proxy63代理对象,第2个是DemoServiceDubboProxy0,$Proxy63是我们业务上的消费端和服务端都用的Dubbo的接口所对应的代理对象,如例子中的org.apache.dubbo.springboot.demo.DemoService,这个代理对象就是上面的$Proxy63,是利用JDK的动态代理生成的。

DemoServiceDubboProxy0是Dubbo自己模拟JDK动态代理,自己实现了一套动态生成Class内容的一个代理类,lazyTarget其实就是上面讲的ref,具体的代码如下:

转存失败,建议直接上传图片文件

/*
 * Decompiled with CFR.
 * 
 * Could not load the following classes:
 *  org.apache.dubbo.springboot.demo.DemoService
 */
package org.apache.dubbo.springboot.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.rpc.service.Destroyable;
import org.apache.dubbo.rpc.service.EchoService;
import org.apache.dubbo.springboot.demo.DemoService;

public class DemoServiceDubboProxy0 implements ClassGenerator.DC,DemoService,EchoService,Destroyable {
    public static Method[] methods;
    private InvocationHandler handler;

    public String sayHello(String string) {
        Object[] objectArray = new Object[]{string};
        Object object = this.handler.invoke(this, methods[0], objectArray);
        return (String)object;
    }

    public CompletableFuture sayHelloAsync(String string) {
        Object[] objectArray = new Object[]{string};
        Object object = this.handler.invoke(this, methods[1], objectArray);
        return (CompletableFuture)object;
    }

    @Override
    public Object $echo(Object object) {
        Object[] objectArray = new Object[]{object};
        Object object2 = this.handler.invoke(this, methods[2], objectArray);
        return object2;
    }

    @Override
    public void $destroy() {
        Object[] objectArray = new Object[]{};
        Object object = this.handler.invoke(this, methods[3], objectArray);
    }

    public DemoServiceDubboProxy0() {
    }

    public DemoServiceDubboProxy0(InvocationHandler invocationHandler) {
        this.handler = invocationHandler;
    }
}

动态生成Class后,在org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getProxy方法里面,利用反射去生成DemoServiceDubboProxy0对象。

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
    try {
        //看这里,invoker是org.apache.dubbo.registry.client.migration.MigrationInvoker
        return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
    } catch (Throwable fromJavassist) {
        // try fall back to JDK proxy factory
        try {
            T proxy = jdkProxyFactory.getProxy(invoker, interfaces);
            logger.error(PROXY_FAILED_JAVASSIST, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy success. " +
                "Interfaces: " + Arrays.toString(interfaces), fromJavassist);
            return proxy;
        } catch (Throwable fromJdk) {
            logger.error(PROXY_FAILED_JAVASSIST, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
                "Interfaces: " + Arrays.toString(interfaces) + " Javassist Error.", fromJavassist);
            logger.error(PROXY_FAILED_JAVASSIST, "", "", "Failed to generate proxy by Javassist failed. Fallback to use JDK proxy is also failed. " +
                "Interfaces: " + Arrays.toString(interfaces) + " JDK Error.", fromJdk);
            throw fromJavassist;
        }
    }
}

转存失败,建议直接上传图片文件

既然是动态代理对象,主要的逻辑也是在java.lang.reflect.InvocationHandler,这里的是org.apache.dubbo.rpc.proxy.InvokerInvocationHandler

public class InvokerInvocationHandler implements InvocationHandler {
    private static final Logger logger = LoggerFactory.getLogger(InvokerInvocationHandler.class);

    //invoker是org.apache.dubbo.registry.client.migration.MigrationInvoker
    private final Invoker<?> invoker;

    private final ServiceModel serviceModel;

    private final String protocolServiceKey;

    public InvokerInvocationHandler(Invoker<?> handler) {
        this.invoker = handler;
        URL url = invoker.getUrl();
        this.protocolServiceKey = url.getProtocolServiceKey();
        this.serviceModel = url.getServiceModel();
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getDeclaringClass() == Object.class) {
            return method.invoke(invoker, args);
        }
        String methodName = method.getName();
        Class<?>[] parameterTypes = method.getParameterTypes();
        if (parameterTypes.length == 0) {
            if ("toString".equals(methodName)) {
                return invoker.toString();
            } else if ("$destroy".equals(methodName)) {
                invoker.destroy();
                return null;
            } else if ("hashCode".equals(methodName)) {
                return invoker.hashCode();
            }
        } else if (parameterTypes.length == 1 && "equals".equals(methodName)) {
            return invoker.equals(args[0]);
        }
        RpcInvocation rpcInvocation = new RpcInvocation(serviceModel, method.getName(), invoker.getInterface().getName(), protocolServiceKey, method.getParameterTypes(), args);

        if (serviceModel instanceof ConsumerModel) {
            rpcInvocation.put(Constants.CONSUMER_MODEL, serviceModel);
            rpcInvocation.put(Constants.METHOD_MODEL, ((ConsumerModel) serviceModel).getMethodModel(method));
        }
        //走这里
        return InvocationUtil.invoke(invoker, rpcInvocation);
    }
}

转存失败,建议直接上传图片文件

然后调用到org.apache.dubbo.registry.client.migration.MigrationInvoker#invoke方法,然后调用到org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker#invoke,

下面的调用过程虽然是根据2.7的源码画的,但是大差不差的调用流程参考一下:

转存失败,建议直接上传图片文件

org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke------>

最终会调用到org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvoke方法,具体看看这个方法,

protected Result doInvoke(final Invocation invocation) throws Throwable {
    RpcInvocation inv = (RpcInvocation) invocation;
    final String methodName = RpcUtils.getMethodName(invocation);
    inv.setAttachment(PATH_KEY, getUrl().getPath());
    inv.setAttachment(VERSION_KEY, version);

    ExchangeClient currentClient;
    if (clients.length == 1) {
        currentClient = clients[0];
    } else {
        currentClient = clients[index.getAndIncrement() % clients.length];
    }
    try {
        boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);

        int timeout = calculateTimeout(invocation, methodName);
        if (timeout <= 0) {
            return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
                "No time left for making the following call: " + invocation.getServiceName() + "."
                    + invocation.getMethodName() + ", terminate directly."), invocation);
        }

        invocation.setAttachment(TIMEOUT_KEY, timeout);
        if (isOneway) {
            boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
            currentClient.send(inv, isSent);
            return AsyncRpcResult.newDefaultAsyncResult(invocation);
        } else {
            //构造一个线程池
            ExecutorService executor = getCallbackExecutor(getUrl(), inv);
            //发送请求,请求到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)方法
            CompletableFuture<AppResponse> appResponseFuture =
                currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
            // save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
            FutureContext.getContext().setCompatibleFuture(appResponseFuture);
            //同步转异步
            AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
            result.setExecutor(executor);
            return result;
        }
    } catch (TimeoutException e) {
        throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    } catch (RemotingException e) {
        throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    }
}

org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)代码:

public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
    if (closed) {
        throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
    }
    // create request.
    //将请求参数包装成Request
    Request req = new Request();
    req.setVersion(Version.getProtocolVersion());
    req.setTwoWay(true);
    req.setData(request);
    //这里很重要,先构造CompletableFuture类型的对象DefaultFuture
    DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
    try {
        //然后利用netty发送请求
        channel.send(req);
    } catch (RemotingException e) {
        future.cancel();
        throw e;
    }
  //然后直接返回future
    return future;
}
public static DefaultFuture newFuture(Channel channel, Request request, int timeout, ExecutorService executor) {
  //构建一个DefaultFuture对象,服务端返回到结果就是会放到这里里面
  final DefaultFuture future = new DefaultFuture(channel, request, timeout);
    future.setExecutor(executor);
    // ThreadlessExecutor needs to hold the waiting future in case of circuit return.
    if (executor instanceof ThreadlessExecutor) {
        ((ThreadlessExecutor) executor).setWaitingFuture(future);
    }
    // timeout check
    //在这里启动dubbo到超时机制,就是个定时任务
    timeoutCheck(future);
    return future;
}
private DefaultFuture(Channel channel, Request request, int timeout) {
    this.channel = channel;
    this.request = request;
    //每次请求到唯一标识,就是接收到服务端请求到时候,用它从org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES里面根据这个id获取DefaultFuture对象,然后把结果放入到DefaultFuture里面
    this.id = request.getId();
    this.timeout = timeout > 0 ? timeout : channel.getUrl().getPositiveParameter(TIMEOUT_KEY, DEFAULT_TIMEOUT);
    // put into waiting map.
    //把创建的放入到org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES,它是个全局对象
    FUTURES.put(id, this);
    CHANNELS.put(id, channel);
}

DefaultFuture对象构造完了,现在回到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int, java.util.concurrent.ExecutorService)方法,该方法构造完DefaultFuture对象后,然后利用netty给服务端发请求后,就直接返回

future这个对象了,存放请求结果的future和发送请求是分异步发送的,没有任何关系,那么怎么拿到服务端返回的结果的呢????? 重点就在两个地方了,1个就是DefaultFuture里面的id,第2个就是org.apache.dubbo.remoting.exchange.support.DefaultFuture#FUTURES

那么先看看,直接返回的这个future对象有什么作用呢?先返回到org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker#doInvok方法,看这行代码:thenApply(obj -> (AppResponse) obj)

ompletableFuture<AppResponse> appResponseFuture =
    currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);

这个thenApply方法方法有啥用呢?它返回到也是一个CompletableFuture对象,相当于把DefaultFuture和这个CompletableFuture对象绑定了在一起,也就是currentClient.request(inv, timeout, executor)返回到对象和appResponseFuture绑定了在一起了,即DefaultFuture有值了那么appResponseFuture也就有值了。那么赋值的动作具体在哪里呢?????回到方法org.apache.dubbo.rpc.protocol.AbstractInvoker#invoke,里面有行代码waitForResultIfSync(asyncResult, invocation);

这里的asyncResult里面包装了上面的appResponseFuture,以及executor,分别放在了org.apache.dubbo.rpc.AsyncRpcResult#responseFutureorg.apache.dubbo.rpc.AsyncRpcResult#executor两个属性里面。

private void waitForResultIfSync(AsyncRpcResult asyncResult, RpcInvocation invocation) {
    if (InvokeMode.SYNC != invocation.getInvokeMode()) {
        return;
    }
    try {
        /*
         * NOTICE!
         * must call {@link java.util.concurrent.CompletableFuture#get(long, TimeUnit)} because
         * {@link java.util.concurrent.CompletableFuture#get()} was proved to have serious performance drop.
         */
        Object timeout = invocation.getObjectAttachmentWithoutConvert(TIMEOUT_KEY);
        if (timeout instanceof Integer) {
            //看这里,调用到org.apache.dubbo.rpc.AsyncRpcResult#get(long, java.util.concurrent.TimeUnit)方法
            asyncResult.get((Integer) timeout, TimeUnit.MILLISECONDS);
        } else {
            asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new RpcException("Interrupted unexpectedly while waiting for remote result to return! method: " +
            invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    } catch (ExecutionException e) {
        Throwable rootCause = e.getCause();
        if (rootCause instanceof TimeoutException) {
            throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " +
                invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        } else if (rootCause instanceof RemotingException) {
            throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " +
                invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        } else {
            throw new RpcException(RpcException.UNKNOWN_EXCEPTION, "Fail to invoke remote method: " +
                invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
        }
    } catch (java.util.concurrent.TimeoutException e) {
        throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " +
            invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
    } catch (Throwable e) {
        throw new RpcException(e.getMessage(), e);
    }
}

org.apache.dubbo.rpc.AsyncRpcResult#get(long, java.util.concurrent.TimeUnit):

public Result get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        if (executor != null && executor instanceof ThreadlessExecutor) {
            ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
            //看这里,最终调用到org.apache.dubbo.remoting.exchange.support.DefaultFuture.doReceived方法,将服务端的返回结果设置到发送请求时候
            //调用的的那个方法org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(java.lang.Object, int, java.util.concurrent.ExecutorService)
            //中生成的DefaultFuture对象中
            threadlessExecutor.waitAndDrain();
        }
        //因此,responseFuture其实就是org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(java.lang.Object, int, java.util.concurrent.ExecutorService)方法的
        //那个DefaultFuture对象,上面已经给这个DefaultFuture设置了响应结果,因此responseFuture也就有值了
        return responseFuture.get(timeout, unit);

org.apache.dubbo.common.threadpool.ThreadlessExecutor#waitAndDrain:

public void waitAndDrain() throws InterruptedException {
    /**
     * Usually, {@link #waitAndDrain()} will only get called once. It blocks for the response for the first time,
     * once the response (the task) reached and being executed waitAndDrain will return, the whole request process
     * then finishes. Subsequent calls on {@link #waitAndDrain()} (if there're any) should return immediately.
     *
     * There's no need to worry that {@link #finished} is not thread-safe. Checking and updating of
     * 'finished' only appear in waitAndDrain, since waitAndDrain is binding to one RPC call (one thread), the call
     * of it is totally sequential.
     */
    if (isFinished()) {
        return;
    }

    Runnable runnable;
    try {
      //看这里
        runnable = queue.take();
    } catch (InterruptedException e) {
        setWaiting(false);
        throw e;
    }

    synchronized (lock) {
        setWaiting(false);
        runnable.run();
    }

    runnable = queue.poll();
    while (runnable != null) {
        runnable.run();
        runnable = queue.poll();
    }
    // mark the status of ThreadlessExecutor as finished.
    setFinished(true);
}

runnable = queue.take();这行代码,其实就是从queue里面去拿任务去执行,那么任务是从哪里放进去的呢????

这就要说到服务端的响应了,当服务端通过netty写回响应的时候,任务就是从org.apache.dubbo.remoting.transport.dispatcher.all.AllChannelHandler.received里面放入的,也就是服务端的netty响应给客户端的netty的时候,走netty 的Handler来放入的ChannelEventRunnable对象。注意,往queue里面放的时候,是netty自己的线程哦,是异步哦,因为异步,所以会在take方法阻塞,直到netty往这个队列里面放任务哦。

所以DefaultFuture有值了那么appResponseFuture绑定的值是还是要看org.apache.dubbo.remoting.transport.dispatcher.ChannelEventRunnable#run方法,具体的注释看自己的源码注释gitee.com/shylovejay/…

最终调用到org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse方法,

static void handleResponse(Channel channel, Response response) throws RemotingException {
    if (response != null && !response.isHeartbeat()) {
        //看这里,org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response, boolean)
        DefaultFuture.received(channel, response);
    }
}

org.apache.dubbo.remoting.exchange.support.DefaultFuture#received(org.apache.dubbo.remoting.Channel, org.apache.dubbo.remoting.exchange.Response, boolean):

public static void received(Channel channel, Response response, boolean timeout) {
    try {
        //看到没,从FUTURES这个全局变量里面根据id获取对应的DefaultFuture对象,这个对象就是在请求的时候
        // 在org.apache.dubbo.remoting.exchange.support.DefaultFuture.DefaultFuture里面放入的
        DefaultFuture future = FUTURES.remove(response.getId());
        if (future != null) {
          //将判断是否超实的定时器关闭
            Timeout t = future.timeoutCheckTask;
            if (!timeout) {
                // decrease Time
                t.cancel();
            }
            //看这里 调用到org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived
            future.doReceived(response);
        } else {
            logger.warn(PROTOCOL_TIMEOUT_SERVER, "", "", "The timeout response finally returned at "
                + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
                + ", response status is " + response.getStatus()
                + (channel == null ? "" : ", channel: " + channel.getLocalAddress()
                + " -> " + channel.getRemoteAddress()) + ", please check provider side for detailed result.");
        }
    } finally {
        CHANNELS.remove(response.getId());
    }
}

org.apache.dubbo.remoting.exchange.support.DefaultFuture#doReceived:

private void doReceived(Response res) {
    if (res == null) {
        throw new IllegalStateException("response cannot be null");
    }
    if (res.getStatus() == Response.OK) {
        //将解码的好的服务端的返回结果设置到该DefaultFuture对象中,具体代码是java.util.concurrent.CompletableFuture.completeValue这个方法
        //complete里面还有一行代码 postComplete();,这行很重要,
        //它作用就是DefaultFuture里面已经有值了,然而在CompletableFuture<AppResponse> appResponseFuture =
        //                    currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);代码中
        //DefaultFuture里面的有包装了一个CompletableFuture,而这个CompletableFuture对象就是上面的appResponseFuture,它
        //在org.apache.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke方法中被包装了在AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);对象中。
        //因此,DefaultFuture里面已经有值,那么appResponseFuture里就有值了,那么从org.apache.dubbo.rpc.AsyncRpcResult.get(long, java.util.concurrent.TimeUnit)方法的
        //responseFuture.get(timeout, unit);代码中就能拿到值了
        this.complete(res.getResult());
    } else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
        this.completeExceptionally(new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage()));
    } else {
        this.completeExceptionally(new RemotingException(channel, res.getErrorMessage()));
    }

    // the result is returning, but the caller thread may still wait
    // to avoid endless waiting for whatever reason, notify caller thread to return.
    if (executor != null && executor instanceof ThreadlessExecutor) {
        ThreadlessExecutor threadlessExecutor = (ThreadlessExecutor) executor;
        if (threadlessExecutor.isWaiting()) {
            threadlessExecutor.notifyReturn(new IllegalStateException("The result has returned, but the biz thread is still waiting" +
                " which is not an expected state, interrupt the thread manually by returning an exception."));
        }
    }
}

现在回到方法org.apache.dubbo.rpc.AsyncRpcResult#get(long, java.util.concurrent.TimeUnit),结果拿到了,那么threadlessExecutor.waitAndDrain();也就结束阻塞了。responseFuture.get(timeout, unit);也就拿到了最终的服务端返回的结果。

拿到结果就万事大吉了吗?当然没有,毕竟服务端要是抛出异常了,我们也要抛出来,所有对结果还是要做进一步的处理的。

直接返回到org.apache.dubbo.rpc.proxy.InvocationUtil#invoke代码,回到return invoker.invoke(rpcInvocation).recreate();这行代码.

public Object recreate() throws Throwable {
    RpcInvocation rpcInvocation = (RpcInvocation) invocation;
    if (InvokeMode.FUTURE == rpcInvocation.getInvokeMode()) {
        return RpcContext.getClientAttachment().getFuture();
    } else if (InvokeMode.ASYNC == rpcInvocation.getInvokeMode()) {
        return createDefaultValue(invocation).recreate();
    }

    //调用到org.apache.dubbo.rpc.AppResponse.recreate方法
    return getAppResponse().recreate();
}

org.apache.dubbo.rpc.AppResponse#recreate:

public Object recreate() throws Throwable {
    //如果exception不为null,说明服务端抛出了业务异常了,所以要像本地调用一样的将这个异常抛出
    //exception和result的值是在org.apache.dubbo.remoting.transport.DecodeHandler.decode方法中解码出来的
    if (exception != null) {
        // fix issue#619
        try {
            Object stackTrace = exception.getStackTrace();
            if (stackTrace == null) {
                exception.setStackTrace(new StackTraceElement[0]);
            }
        } catch (Exception e) {
            // ignore
        }
        throw exception;
    }
    //如果没有异常,将结果返回过去
    return result;
}

好了,结束。

Dubbo3.0的注册中心监听

消费者:

消费者是一定要一直监听注册中心来实时感知提供者配置的变化的,包括提供者的下线和上线的,从而实时改变自己的调用策略,调用参数等等。

那么监听注册中心哪里呢?不同的注册中心实现不同,但是统一的入口是在org.apache.dubbo.registry.integration.RegistryProtocol#doCreateInvoker方法。

protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
    // DynamicDirectory directory动态服务目录有两种:RegistryDirectory和ServiceDiscoveryRegistryDirectory
    // RegistryDirectory用来记录和监听接口级服务提供者地址
    // ServiceDiscoveryRegistryDirectory用来记录和监听应用级服务提供者地址
    // Registry registry也有两种:ListenerRegistryWrapper,它里面包装了ZookeeperRegistry、NacosRegistry这种注册中心的,继承了FailbackRegistry,和ServiceDiscoveryRegistry,也继承了FailbackRegistry
    // 一个DynamicDirectory中包含一个Registry,Registry用来同步远程注册中心的数据,所以需要监听数据的变化
    directory.setRegistry(registry);
    directory.setProtocol(protocol);
    // all attributes of REFER_KEY
    //获取消费端的参数{side=consumer, register.ip=192.168.3.12, release=3.1.2-SNAPSHOT, methods=sayHello, dubbo=2.0.2, pid=17876, interface=org.apache.dubbo.springboot.demo.DemoService, qos.enable=true, unloadClusterRelated=false, application=dubbo-springboot-demo-consumer, background=false, sticky=false, timestamp=1669280017621}
    Map<String, String> parameters = new HashMap<>(directory.getConsumerUrl().getParameters());
    //构造出要注册到注册中心的consumer的url,consumer://192.168.3.12/org.apache.dubbo.springboot.demo.DemoService?application=dubbo-springboot-demo-consumer&background=false&dubbo=2.0.2&interface=org.apache.dubbo.springboot.demo.DemoService&methods=sayHello&pid=17876&qos.enable=true&release=3.1.2-SNAPSHOT&side=consumer&sticky=false&timestamp=1669280017621&unloadClusterRelated=false
    URL urlToRegistry = new ServiceConfigURL(
        parameters.get(PROTOCOL_KEY) == null ? CONSUMER : parameters.get(PROTOCOL_KEY),
        parameters.remove(REGISTER_IP_KEY),
        0,
        getPath(parameters, type),
        parameters
    );
    urlToRegistry = urlToRegistry.setScopeModel(directory.getConsumerUrl().getScopeModel());
    urlToRegistry = urlToRegistry.setServiceModel(directory.getConsumerUrl().getServiceModel());
    if (directory.isShouldRegister()) {
        directory.setRegisteredConsumerUrl(urlToRegistry);
        //对于zk,将consumer对应的url注册到zk,对应的节点是/dubbo/org.apache.dubbo.springboot.demo.DemoService/consumers/consumer%3A%2F%2F192.168.3.12%2Forg.apache.dubbo.springboot.demo.DemoService%3Fapplication%3Ddubbo-springboot-demo-consumer%26background%3Dfalse%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26interface%3Dorg.apache.dubbo.springboot.demo.DemoService%26methods%3DsayHello%26pid%3D17876%26qos.enable%3Dtrue%26release%3D3.1.2-SNAPSHOT%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1669280017621%26unloadClusterRelated%3Dfalse
        //对于nacos,调用到org.apache.dubbo.registry.nacos.NacosNamingServiceWrapper#registerInstance,注册到
        //分组DEFAULT_GROUP,服务名为consumers:org.apache.dubbo.springboot.demo.DemoService::
        registry.register(directory.getRegisteredConsumerUrl());
    }
    directory.buildRouterChain(urlToRegistry);
    // 监听相应的注册中心目录,触发生成Invoker
    //在这里启动netty客户端的
    //toSubscribeUrl(urlToRegistry)方法给urlToRegistry添加了category=providers,configurators,routers参数
    // consumer://192.168.3.12/org.apache.dubbo.springboot.demo.DemoService?application=dubbo-springboot-demo-consumer&background=false&category=providers,configurators,routers&dubbo=2.0.2&interface=org.apache.dubbo.springboot.demo.DemoService&methods=sayHello&pid=17876&qos.enable=true&release=3.1.2-SNAPSHOT&side=consumer&sticky=false&timestamp=1669280017621&unloadClusterRelated=false
    //对于zk,监听的路径是/dubbo/org.apache.dubbo.springboot.demo.DemoService/providers
    //          /dubbo/org.apache.dubbo.springboot.demo.DemoService/configurators
    //          /dubbo/org.apache.dubbo.springboot.demo.DemoService/routers
    //对于nacos,监听的是DEFAULT_GROUP下面的名字为providers:org.apache.dubbo.springboot.demo.DemoService::,             providers:org.apache.dubbo.springboot.demo.DemoService这两个服务
    directory.subscribe(toSubscribeUrl(urlToRegistry));

    //调用到org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper.join方法
    return (ClusterInvoker<T>) cluster.join(directory, true);
}

directory.subscribe(toSubscribeUrl(urlToRegistry));这行代码就是去注册中心监听提供者的动态了。

nacos:

对于nacos,监听的代码最终会调用到com.alibaba.nacos.client.naming.NacosNamingService#subscribe(java.lang.String, java.lang.String, java.util.List<java.lang.String>, com.alibaba.nacos.api.naming.listener.EventListener)方法。

public void subscribe(String serviceName, String groupName, List<String> clusters, EventListener listener)
        throws NacosException {
    if (null == listener) {
        return;
    }
    String clusterString = StringUtils.join(clusters, ",");
    //看这里,先注册监听器,注意,这个listener里面就包装了我们的RegistryDirectory
    //将这个listter对象@11615,放入到com.alibaba.nacos.client.naming.event.InstancesChangeNotifier#listenerMap这个Map中,key是DEFAULT_GROUP@@providers:org.apache.dubbo.springboot.demo.DemoService::
    changeNotifier.registerListener(groupName, serviceName, clusterString, listener);
    //看这里
    clientProxy.subscribe(serviceName, groupName, clusterString);
}

转存失败,建议直接上传图片文件

接着看com.alibaba.nacos.client.naming.remote.NamingClientProxyDelegate#subscribe方法:

public ServiceInfo subscribe(String serviceName, String groupName, String clusters) throws NacosException {
    NAMING_LOGGER.info("[SUBSCRIBE-SERVICE] service:{}, group:{}, clusters:{} ", serviceName, groupName, clusters);
    String serviceNameWithGroup = NamingUtils.getGroupedName(serviceName, groupName);
    String serviceKey = ServiceInfo.getKey(serviceNameWithGroup, clusters);
    //看这行代码 
    serviceInfoUpdateService.scheduleUpdateIfAbsent(serviceName, groupName, clusters);
    ServiceInfo result = serviceInfoHolder.getServiceInfoMap().get(serviceKey);
    if (null == result || !isSubscribed(serviceName, groupName, clusters)) {
        result = grpcClientProxy.subscribe(serviceName, groupName, clusters);
    }
    serviceInfoHolder.processServiceInfo(result);
    return result;
}

com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService#scheduleUpdateIfAbsent方法:

public void scheduleUpdateIfAbsent(String serviceName, String groupName, String clusters) {
    if (!asyncQuerySubscribeService) {
        return;
    }
    String serviceKey = ServiceInfo.getKey(NamingUtils.getGroupedName(serviceName, groupName), clusters);
    if (futureMap.get(serviceKey) != null) {
        return;
    }
    synchronized (futureMap) {
        if (futureMap.get(serviceKey) != null) {
            return;
        }
        //看这里的UpdateTask,它是个Runnable,addTask方法会启动这个Runnable,直接看它的run方法
        ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, groupName, clusters));
        futureMap.put(serviceKey, future);
    }
}

com.alibaba.nacos.client.naming.core.ServiceInfoUpdateService.UpdateTask#run方法:

public void run() {
    long delayTime = DEFAULT_DELAY;
    
    try {
        if (!changeNotifier.isSubscribed(groupName, serviceName, clusters) && !futureMap.containsKey(
                serviceKey)) {
            NAMING_LOGGER.info("update task is stopped, service:{}, clusters:{}", groupedServiceName, clusters);
            isCancel = true;
            return;
        }
        
        ServiceInfo serviceObj = serviceInfoHolder.getServiceInfoMap().get(serviceKey);
        if (serviceObj == null) {
            serviceObj = namingClientProxy.queryInstancesOfService(serviceName, groupName, clusters, 0, false);
            serviceInfoHolder.processServiceInfo(serviceObj);
            lastRefTime = serviceObj.getLastRefTime();
            return;
        }
        
        if (serviceObj.getLastRefTime() <= lastRefTime) {
            serviceObj = namingClientProxy.queryInstancesOfService(serviceName, groupName, clusters, 0, false);
           //看这里
            serviceInfoHolder.processServiceInfo(serviceObj);
        }
        lastRefTime = serviceObj.getLastRefTime();
        if (CollectionUtils.isEmpty(serviceObj.getHosts())) {
            incFailCount();
            return;
        }
        // TODO multiple time can be configured.
        delayTime = serviceObj.getCacheMillis() * DEFAULT_UPDATE_CACHE_TIME_MULTIPLE;
        resetFailCount();
    } catch (NacosException e) {
        handleNacosException(e);
    } catch (Throwable e) {
        handleUnknownException(e);
    } finally {
        if (!isCancel) {
            executor.schedule(this, Math.min(delayTime << failCount, DEFAULT_DELAY * 60),
                    TimeUnit.MILLISECONDS);
        }
    }
}

com.alibaba.nacos.client.naming.cache.ServiceInfoHolder#processServiceInfo(com.alibaba.nacos.api.naming.pojo.ServiceInfo)方法:

public ServiceInfo processServiceInfo(ServiceInfo serviceInfo) {
    String serviceKey = serviceInfo.getKey();
    if (serviceKey == null) {
        return null;
    }
    ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());
    if (isEmptyOrErrorPush(serviceInfo)) {
        //empty or error push, just ignore
        return oldService;
    }
    serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
    boolean changed = isChangedServiceInfo(oldService, serviceInfo);
    if (StringUtils.isBlank(serviceInfo.getJsonFromServer())) {
        serviceInfo.setJsonFromServer(JacksonUtils.toJson(serviceInfo));
    }
    MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size());
    if (changed) {//与本地缓存的提供者的配置相比,如果注册中心的提供者的配置发生变化,则发布一个InstancesChangeEvent事件
        NAMING_LOGGER.info("current ips:({}) service: {} -> {}", serviceInfo.ipCount(), serviceInfo.getKey(),
                JacksonUtils.toJson(serviceInfo.getHosts()));
        //发布一个InstancesChangeEvent事件
        NotifyCenter.publishEvent(new InstancesChangeEvent(notifierEventScope, serviceInfo.getName(), serviceInfo.getGroupName(),
                serviceInfo.getClusters(), serviceInfo.getHosts()));
        DiskCache.write(serviceInfo, cacheDir);
    }
    return serviceInfo;
}

最终调用到com.alibaba.nacos.common.notify.DefaultPublisher#publish方法:

注意com.alibaba.nacos.common.notify.DefaultPublisher其实是个Runnable

public boolean publish(Event event) {
    checkIsStart();
    //发布事件,其实就是放入到,com.alibaba.nacos.common.notify.DefaultPublisher#queue这个队列中
    //那么既然有放入到,又是哪里拿出来的呢?
    boolean success = this.queue.offer(event);
    if (!success) {
        LOGGER.warn("Unable to plug in due to interruption, synchronize sending time, event : {}", event);
        receiveEvent(event);
        return true;
    }
    return true;
}

com.alibaba.nacos.common.notify.DefaultPublisher既然是个Runnable,那么肯定有个地方会启动,在哪里呢??

其实就是在com.alibaba.nacos.common.notify.DefaultPublisher#init方法中,直接启动的。

public void init(Class<? extends Event> type, int bufferSize) {
    setDaemon(true);
    setName("nacos.publisher-" + type.getName());
    this.eventType = type;
    this.queueMaxSize = bufferSize;
    this.queue = new ArrayBlockingQueue<>(bufferSize);
    start();
}

现在看看怎么从里面取到任务去执行的,

public void run() {
    openEventHandler();
}

void openEventHandler() {
    try {
        
        // This variable is defined to resolve the problem which message overstock in the queue.
        int waitTimes = 60;
        // To ensure that messages are not lost, enable EventHandler when
        // waiting for the first Subscriber to register
        for (; ; ) {
            if (shutdown || hasSubscriber() || waitTimes <= 0) {
                break;
            }
            ThreadUtils.sleep(1000L);
            waitTimes--;
        }
        
        for (; ; ) {
            if (shutdown) {
                break;
            }
            //这就首尾呼应上了,从里面取得InstancesChangeEvent事件
            final Event event = queue.take();
            //开始处理
            receiveEvent(event);
            UPDATER.compareAndSet(this, lastEventSequence, Math.max(lastEventSequence, event.sequence()));
        }
    } catch (Throwable ex) {
        LOGGER.error("Event listener exception : ", ex);
    }
}

调用com.alibaba.nacos.client.naming.event.InstancesChangeNotifier#onEvent方法,

public void onEvent(InstancesChangeEvent event) {
    String key = ServiceInfo
            .getKey(NamingUtils.getGroupedName(event.getServiceName(), event.getGroupName()), event.getClusters());
    //这又首尾呼应上了,从com.alibaba.nacos.client.naming.event.InstancesChangeNotifier#listenerMap获取监听者,看到没,他就是@11615那个对象
    //key是DEFAULT_GROUP@@providers:org.apache.dubbo.springboot.demo.DemoService::
    ConcurrentHashSet<EventListener> eventListeners = listenerMap.get(key);
    if (CollectionUtils.isEmpty(eventListeners)) {
        return;
    }
    for (final EventListener listener : eventListeners) {
        final com.alibaba.nacos.api.naming.listener.Event namingEvent = transferToNamingEvent(event);
        if (listener instanceof AbstractEventListener && ((AbstractEventListener) listener).getExecutor() != null) {
            ((AbstractEventListener) listener).getExecutor().execute(() -> listener.onEvent(namingEvent));
        } else {
            //调用到org.apache.dubbo.registry.nacos.NacosRegistry.RegistryChildListenerImpl#onEvent方法 
            //它既是@11615那个对象
            listener.onEvent(namingEvent);
        }
    }
}

转存失败,建议直接上传图片文件

最终会调用到org.apache.dubbo.registry.integration.RegistryDirectory#notify方法,去重新生成消费端端invoker对象,

public synchronized void notify(List<URL> urls) {
    if (isDestroyed()) {
        return;
    }

    Map<String, List<URL>> categoryUrls = urls.stream()
        .filter(Objects::nonNull)
        .filter(this::isValidCategory)
        .filter(this::isNotCompatibleFor26x)
        .collect(Collectors.groupingBy(this::judgeCategory));

    List<URL> configuratorURLs = categoryUrls.getOrDefault(CONFIGURATORS_CATEGORY, Collections.emptyList());
    this.configurators = Configurator.toConfigurators(configuratorURLs).orElse(this.configurators);

    List<URL> routerURLs = categoryUrls.getOrDefault(ROUTERS_CATEGORY, Collections.emptyList());
    toRouters(routerURLs).ifPresent(this::addRouters);

    // providers
    List<URL> providerURLs = categoryUrls.getOrDefault(PROVIDERS_CATEGORY, Collections.emptyList());

    // 3.x added for extend URL address
    ExtensionLoader<AddressListener> addressListenerExtensionLoader = getUrl().getOrDefaultModuleModel().getExtensionLoader(AddressListener.class);
    List<AddressListener> supportedListeners = addressListenerExtensionLoader.getActivateExtension(getUrl(), (String[]) null);
    if (supportedListeners != null && !supportedListeners.isEmpty()) {
        for (AddressListener addressListener : supportedListeners) {
            providerURLs = addressListener.notify(providerURLs, getConsumerUrl(), this);
        }
    }
  //重新去生成invoker
    refreshOverrideAndInvoker(providerURLs);
}

转存失败,建议直接上传图片文件