dubbo Proxy Wrapper 代理类源码分析

1,894 阅读6分钟

动态代理回顾

  • 几乎所有java相关框架都需要采用动态代理工具; 【个人理解有以下两点】
    • 强类型:java是强类型语言,在编译阶段有类型检测
    • 切面编程:在用户代码执行之前、之后... 织入通用处理逻辑
  • jdk动态代理相关类有java.lang.reflect.Proxy,java.lang.reflect.InvocationHandler
  • jdk创建代理类需要实现InvocationHandler接口,并作为参数进一步可创建对应代理Proxy类
  • InvocationHandler :Object invoke(Object proxy, Method method, Object[] args) 只有一个接口方法, 通常我们只需实现该方法,不会显式调用,proxy对象会调用该方法
    • proxy:被代理对象 可进行嵌套如 proxy1 -> proxy2 -> ... -> originObject
    • 当调用proxy对象方法时,会调用到InvocationHandler#invoke 方法
  • jdk动态代理需要有接口定义;Javassist或asm 组件可以没有接口
  • 动态代理相关文档链接

概述

  • dubbo提供的动态代理工厂有JdkProxyFactory,JavassistProxyFactory
  • 通过ProxyFactory接口的@SPI注解可看到默认实现是JavassistProxyFactory
  • 使用Javassist生成代理类文件的核心类有 Proxy, Wrapper

dubbo 动态代理层的作用与必要性

  • 图中的rpc调用没画出序列化、网络层... 【本文忽略】

  • proxy-client,proxy-server仅表示RPC框架中代理层;具体创建的代理对象会有很多个

  • 客户端与服务端通常部署在不同服务器上,那么接口调用与实现需要发送网络请求

  • client端调用rpc方法时:

    • 可显式调用rpc接口每个方法,实际是调用代理类的方法【必须有rpc接口实现类代理】
    • method通常拆解为 类、方法名、参数、返回值类型...等数据
    • 任何接口方法在proxy中无非是className,methodName,paramType, paramValue... 等数据;
    • 由具体接口方法 ---> 代理对象方法 ---> 封装方法数据为req ---> send req
  • server端接收到rpc方法请求时:

    • 解析req方法数据,并创建对应代理对象;
    • 为什么不创建具体的rpc接口实现类对象?框架代码内部没法调用具体实现类的方法,只能调用代理类Proxy的方法;
    • Proxy在用户代码运行时采用反射引用到具体的实现类
    • receive req ---> 解析req数据 ---> 代理对象 ---> 接口实现类

dubbo动态代理

  • ProxyFactory默认采用JavassistProxyFactory实现

    @SPI("javassist")
    public interface ProxyFactory {
    
        // 阅读代码过程中 发现该方法在服务引用阶段调用多一些【有例外】
        // 若在服务引用阶段调用,通常需要根据引用rpc接口创建对应的invoker实例
        // 创建非范化调用代理对象
        @Adaptive({PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker) throws RpcException;
    
        // 阅读代码过程中 发现该方法在服务引用阶段调用多一些【有例外】
        // 若在服务引用阶段调用,通常需要根据引用rpc接口创建对应的invoker实例
        // generic: 控制是否范化代理对象
        @Adaptive({PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
    
        // 阅读代码过程中 发现该方法在服务暴露阶段调用多一些【有例外】
        // proxy:rpc接口实现类,或其他...
        @Adaptive({PROXY_KEY})
        <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
    
    }
    
  • JavassistProxyFactory 有出现两个核心类Proxy,Wrapper

  • 注意Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); 返回值不是Proxy类型

    public class JavassistProxyFactory extends AbstractProxyFactory {
    
        @Override
        public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
            // Proxy#getProxy 返回 Proxy对象        
            // 在调用newInstance方法传入 invoker【被代理对象】
            // 【重点】生成具体代理对象【具体代理类的 ClassType 不是 org.apache.dubbo.common.bytecode.Proxy】
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }
    
        @Override
        public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
            // 创建Wrapper包装类【请注意:不需要用到具体的 proxy引用,只需className即可】
            final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
            // 创建Invoker对象,此处需要传入被代理对象proxy【如:rpc接口实现类】
            return new AbstractProxyInvoker<T>(proxy, type, url) {
    
                // 该方法类似与 InvocationHandler :Object invoke(Object proxy, Method method, Object[] args)
                @Override
                protected Object doInvoke(T proxy, String methodName,
                                          Class<?>[] parameterTypes,
                                          Object[] arguments) throws Throwable {
                    // AbstractProxyInvoker#invoke方法会调用doInvoke方法
                    // doInvoke方法会调用wrapper#invokeMethod
                    // wrapper#invokeMethod方法会调用proxy对应的方法
                    return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
                }
            };
        }
    
    }
    

dubbo Wrapper代理类创建分析

  • testDemoProtocol方法中执行protocol.export(invoker) 方法时需要传入invoker

  • 该invoker通过proxyFactory.getInvoker(***)进行创建【通常proxyFactory.getInvoker 在服务暴露阶段会被调用到;也有例外】

  • 默认调用JavassistProxyFactory#getInvoker方法;进一步调用Wrapper相关方法

    public class DubboProtocolTest {
        private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
        private ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    
        @Test
        public void testDemoProtocol() throws Exception {
            // 接口实现对象【被代理对象】
            DemoService service = new DemoServiceImpl();
            int port = NetUtils.getAvailablePort();
            // 分析入口:服务暴露阶段调用 Proxy#getInvoker【有例外】
            protocol.export(proxyFactory.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange")));
            service = proxyFactory.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
                    3000L)));
            assertEquals(service.getSize(new String[]{"", "", ""}), 3);
        }
        。。。
    }
    

org.apache.dubbo.common.bytecode.Wrapper

  • proxy.getInvoker(***) 会执行Wrapper#getWrapper方法

  • Wrapper#makeWrapper 主要调用javassist api 生成动态代理类

  • debug到 cc.toClass() 时手动运行cc.mCtc.writeFile("/doc"); 则会在/doc/** 相关目录看到Wrapper*.class 文件

    public abstract class Wrapper {
        private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
        private static final String[] EMPTY_STRING_ARRAY = new String[0];
        private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
        private static AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0);
    
        // 此处的参数对象Class 通常是被代理【如:rpc接口实现类】对象的class
        public static Wrapper getWrapper(Class<?> c) {
           // 已经是动态代理类型则返回
            while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
            {
                c = c.getSuperclass();
            }
    
            if (c == Object.class) {
                return OBJECT_WRAPPER;
            }
            // 会有缓存
            return WRAPPER_MAP.computeIfAbsent(c, key -> makeWrapper(key));
        }
    
        // 创建动态代理Wrapper类
        // 调用Javassist工具类生成class文件,该方法很长 【已删除很多代码】
        // 对Javassist api感兴趣的读者可阅读源码
        private static Wrapper makeWrapper(Class<?> c) {
            if (c.isPrimitive()) {
                throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
            }
    
            String name = c.getName();
            ClassLoader cl = ClassUtils.getClassLoader(c);
    
            StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
            StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
            StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
    
            c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
            c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
    
            Map<String, Class<?>> pts = new HashMap<>(); // <property name, property types>
            Map<String, Method> ms = new LinkedHashMap<>(); // <method desc, Method instance>
            List<String> mns = new ArrayList<>(); // method names.
            List<String> dmns = new ArrayList<>(); // declaring method names.
    
            for (Map.Entry<String, Method> entry : ms.entrySet()) {
                。。。
            }
    
            long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
            ClassGenerator cc = ClassGenerator.newInstance(cl);
            // 动态代理类名通常为Wrapper0,Wrapper1 ...
            // 动态代理类 与Wrapper在同一个包下
            cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
            // 动态代理类extends Wrapper
            cc.setSuperClass(Wrapper.class);
    
            try {
                // 生成Class类
                // debug到此处手动运行 cc.mCtc.writeFile("/doc"); 可生成动态代理类class文件 反编译可看到对应代码
                Class<?> wc = cc.toClass();
                // setup static field.
                wc.getField("pts").set(null, pts);
                wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
                wc.getField("mns").set(null, mns.toArray(new String[0]));
                wc.getField("dmns").set(null, dmns.toArray(new String[0]));
                int ix = 0;
                for (Method m : ms.values()) {
                    wc.getField("mts" + ix++).set(null, m.getParameterTypes());
                }
                return (Wrapper) wc.newInstance();
            } catch (RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                cc.release();
                ms.clear();
                mns.clear();
                dmns.clear();
            }
        }
        //final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass()); 会实现该类
        // instance 【被代理对象】
        abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
    }
    

Wrapper创建的动态代理文件 Wrapper0.class 【反编译如下】

  • Wrapper0是通过调用 Wrapper.getWrapper(DemoServiceImpl.class) 生成的类【通常在服务暴露过程中调用该方法,将所有的rpc接口实现类统一转换成Wrapper的子类】

  • Wrapper0中的每个方法内,都有将参数转成DemoServiceImpl 类型的代码行

  • 在代理类class实例【如:Wrapper0】与代理类实例 创建阶段只需要传入 被代理对象的class类型;【形式参数】

  • Wrapper0#invokeMethod方法执行时需要传入 被代理对象实例 【实际参数】

  • Wrapper0 没有将被代理对象实例作为属性;而 Proxy生成代理对象有将被代理对象实例作为属性

    // 与Wrapper在同一个package下
    package org.apache.dubbo.common.bytecode;
    
    import java.lang.reflect.InvocationTargetException;
    import java.util.Map;
    import org.apache.dubbo.rpc.protocol.dubbo.support.CustomArgument;
    import org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl;
    import org.apache.dubbo.rpc.protocol.dubbo.support.Man;
    import org.apache.dubbo.rpc.protocol.dubbo.support.NonSerialized;
    import org.apache.dubbo.rpc.protocol.dubbo.support.Person;
    import org.apache.dubbo.rpc.protocol.dubbo.support.Type;
    
    // 实现ClassGenerator.DC接口 表示Wrapper0是动态代理类
    public class Wrapper0 extends Wrapper implements ClassGenerator.DC {
      public static String[] pns;
    
      public static Map pts;
    
      public static String[] mns;
    
      public static String[] dmns;
    
      public static Class[] mts0;
    
      public static Class[] mts1;
    
      public static Class[] mts2;
    
      public static Class[] mts3;
    
      public static Class[] mts4;
    
      public static Class[] mts5;
    
      public static Class[] mts6;
    
      public static Class[] mts7;
    
      public static Class[] mts8;
    
      public static Class[] mts9;
    
      public static Class[] mts10;
    
      public static Class[] mts11;
    
      public static Class[] mts12;
    
      public static Class[] mts13;
    
      public static Class[] mts14;
    
      public static Class[] mts15;
    
      public static Class[] mts16;
    
      public static Class[] mts17;
    
      public static Class[] mts18;
    
      public static Class[] mts19;
    
      public static Class[] mts20;
    
      public static Class[] mts21;
    
      public String[] getPropertyNames() { return pns; }
    
      public boolean hasProperty(String paramString) { return pts.containsKey(paramString); }
    
      public Class getPropertyType(String paramString) { return (Class)pts.get(paramString); }
    
      public String[] getMethodNames() { return mns; }
    
      public String[] getDeclaredMethodNames() { return dmns; }
    
      public void setPropertyValue(Object paramObject1, String paramString, Object paramObject2) {
        try {
          DemoServiceImpl demoServiceImpl = (DemoServiceImpl)paramObject1;
        } catch (Throwable throwable) {
          throw new IllegalArgumentException(throwable);
        } 
        throw new NoSuchPropertyException("Not found property \"" + paramString + "\" field or setter method in class org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl.");
      }
    
      public Object getPropertyValue(Object paramObject, String paramString) {
        DemoServiceImpl demoServiceImpl;
        try {
          demoServiceImpl = (DemoServiceImpl)paramObject;
        } catch (Throwable throwable) {
          throw new IllegalArgumentException(throwable);
        } 
        if (paramString.equals("threadName"))
          return demoServiceImpl.getThreadName(); 
        if (paramString.equals("remoteApplicationName"))
          return demoServiceImpl.getRemoteApplicationName(); 
        throw new NoSuchPropertyException("Not found property \"" + paramString + "\" field or setter method in class org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl.");
      }
    
      // 所有DemoService方法调用入口
      public Object invokeMethod(Object paramObject, String paramString, Class[] paramArrayOfClass, Object[] paramArrayOfObject) throws InvocationTargetException {
        // 执行到 Wrapper.getWrapper(DemoServiceImpl.class);
        // Wrapper0 中所有方法内部均调用 demoServiceImpl 对应方法
        DemoServiceImpl demoServiceImpl;
        try {
          demoServiceImpl = (DemoServiceImpl)paramObject;
        } catch (Throwable throwable) {
          throw new IllegalArgumentException(throwable);
        } 
        // 看到这么一串if else 也有点醉了
        // 下列方法名中有DemoService接口的所有方法
        // 还拥有 EchoService【回声接口】,Destroyable【可销毁接口】对应方法
        // AbstractProxyFactory 有添加 *EchoService, Destroyable* 的代码
        try {
          if (!"invoke".equals(paramString) || paramArrayOfClass.length != 2) {
            if (!"add".equals(paramString) || paramArrayOfClass.length != 2) {
              if (!"get".equals(paramString) || paramArrayOfClass.length != 1) {
                if (!"getInt".equals(paramString) || paramArrayOfClass.length != 1) {
                  if (!"timestamp".equals(paramString) || paramArrayOfClass.length != 0) {
                    if (!"keys".equals(paramString) || paramArrayOfClass.length != 1) {
                      if (!"getType".equals(paramString) || paramArrayOfClass.length != 1) {
                        if (!"getSize".equals(paramString) || paramArrayOfClass.length != 1 || !paramArrayOfClass[0].getName().equals("[Ljava.lang.Object;")) {
                          if (!"getSize".equals(paramString) || paramArrayOfClass.length != 1 || !paramArrayOfClass[0].getName().equals("[Ljava.lang.String;")) {
                            if (!"getPerson".equals(paramString) || paramArrayOfClass.length != 2 || !paramArrayOfClass[0].getName().equals("org.apache.dubbo.rpc.protocol.dubbo.support.Person") || !paramArrayOfClass[1].getName().equals("org.apache.dubbo.rpc.protocol.dubbo.support.Person")) {
                              if (!"getPerson".equals(paramString) || paramArrayOfClass.length != 1 || !paramArrayOfClass[0].getName().equals("org.apache.dubbo.rpc.protocol.dubbo.support.Man")) {
                                if (!"getPerson".equals(paramString) || paramArrayOfClass.length != 1 || !paramArrayOfClass[0].getName().equals("org.apache.dubbo.rpc.protocol.dubbo.support.Person")) {
                                  if (!"getThreadName".equals(paramString) || paramArrayOfClass.length != 0) {
                                    if (!"echo".equals(paramString) || paramArrayOfClass.length != 1 || !paramArrayOfClass[0].getName().equals("java.lang.String")) {
                                      if (!"echo".equals(paramString) || paramArrayOfClass.length != 1 || !paramArrayOfClass[0].getName().equals("java.util.Map")) {
                                        if (!"enumlength".equals(paramString) || paramArrayOfClass.length != 1) {
                                          if (!"stringLength".equals(paramString) || paramArrayOfClass.length != 1) {
                                            if (!"sayHello".equals(paramString) || paramArrayOfClass.length != 1) {
                                              if (!"nonSerializedParameter".equals(paramString) || paramArrayOfClass.length != 1) {
                                                if (!"returnNonSerialized".equals(paramString) || paramArrayOfClass.length != 0) {
                                                  if (!"getRemoteApplicationName".equals(paramString) || paramArrayOfClass.length != 0) {
                                                    if (!"gerPerson".equals(paramString) || paramArrayOfClass.length != 1)
                                                      throw new NoSuchMethodException("Not found method \"" + paramString + "\" in class org.apache.dubbo.rpc.protocol.dubbo.support.DemoServiceImpl."); 
                                                    return demoServiceImpl.gerPerson((Person)paramArrayOfObject[0]);
                                                  } 
                                                  return demoServiceImpl.getRemoteApplicationName();
                                                } 
                                                return demoServiceImpl.returnNonSerialized();
                                              } 
                                              demoServiceImpl.nonSerializedParameter((NonSerialized)paramArrayOfObject[0]);
                                              return null;
                                            } 
                                            demoServiceImpl.sayHello((String)paramArrayOfObject[0]);
                                            return null;
                                          } 
                                          new Integer();
                                          super(new Integer());
                                          return new Integer();
                                        } 
                                        return demoServiceImpl.enumlength((Type[])paramArrayOfObject[0]);
                                      } 
                                      return demoServiceImpl.echo((Map)paramArrayOfObject[0]);
                                    } 
                                    return demoServiceImpl.echo((String)paramArrayOfObject[0]);
                                  } 
                                  return demoServiceImpl.getThreadName();
                                } 
                                new Integer();
                                super(new Integer());
                                return new Integer();
                              } 
                              return demoServiceImpl.getPerson((Man)paramArrayOfObject[0]);
                            } 
                            new Integer();
                            super(new Integer());
                            return new Integer();
                          } 
                          new Integer();
                          super(new Integer());
                          return new Integer();
                        } 
                        new Integer();
                        super(new Integer());
                        return new Integer();
                      } 
                      return demoServiceImpl.getType((Type)paramArrayOfObject[0]);
                    } 
                    return demoServiceImpl.keys((Map)paramArrayOfObject[0]);
                  } 
                  new Long();
                  super(new Long());
                  return new Long();
                } 
                new Integer();
                super(new Integer());
                return new Integer();
              } 
              return demoServiceImpl.get((CustomArgument)paramArrayOfObject[0]);
            } 
            new Long();
            super(new Long());
            return new Long();
          } 
          return demoServiceImpl.invoke((String)paramArrayOfObject[0], (String)paramArrayOfObject[1]);
        } catch (Throwable throwable) {
          throw new InvocationTargetException(throwable);
        } 
      }
    }
    

dubbo Proxy代理类创建分析

  • testDemoProtocol方法中执行protocol.refer(***) 生成Invoke对象

  • proxyFactory#getProxy --> Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));

  • invoke作为被代理对象 调用proxyFactory.getProxy(invoke) 从而生成proxy对象 【通常在服务应用阶段被调用到;也有例外】

  • 【注意】Proxy.getProxy(interfaces) 返回值是Proxy的子类,

  • 【注意】newInstance(new InvokerInvocationHandler(invoker)); 返回值是 具体接口【interfaces】的实现类

    public class DubboProtocolTest {
        private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
        private ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    
        @Test
        public void testDemoProtocol() throws Exception {
            DemoService service = new DemoServiceImpl();
            int port = NetUtils.getAvailablePort();
            protocol.export(proxyFactory.getInvoker(service, DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange")));
            // 分析入口:服务引用阶段调用 proxyFactory#getProxy【有例外】
            service = proxyFactory.getProxy(protocol.refer(DemoService.class, URL.valueOf("dubbo://127.0.0.1:" + port + "/" + DemoService.class.getName() + "?codec=exchange").addParameter("timeout",
                    3000L)));
            assertEquals(service.getSize(new String[]{"", "", ""}), 3);
        }
        。。。
    }
    

org.apache.dubbo.common.bytecode.Proxy

  • 入口方法:Proxy#getProxy

  • Proxy 也采用Javassist生成代理对象

  • Proxy#getProxy 中有两次调用org.apache.dubbo.common.bytecode.ClassGenerator#toClass();【ccp.toClass(); 与 ccm.toClass();】

  • 两次调用toClass是比较容易让读者迷惑的地方

  • 注意ccp.toClass 是 org.apache.dubbo.common.bytecode.proxy0类型【小写p】

  • 注意ccm.toClass 是 org.apache.dubbo.common.bytecode.Proxy0类型【大写P】

  • debug toClass 手动执行ccm.mCtc.writeFile("/doc"); ccp.mCtc.writeFile("/doc"); 可生成对应的class文件

    public abstract class Proxy {
    
        private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
        private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
        // 代理生成缓存
        private static final Map<ClassLoader, Map<String, Object>> PROXY_CACHE_MAP = new WeakHashMap<ClassLoader, Map<String, Object>>();
    
        private static final Object PENDING_GENERATION_MARKER = new Object();
    
        protected Proxy() {
        }
        。。。
    
        /**
         * Get proxy.
         *
         * @param ics interface class array.
         * @return Proxy instance.
         */
        public static Proxy getProxy(Class<?>... ics) {
            return getProxy(ClassUtils.getClassLoader(Proxy.class), ics);
        }
    
        public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
            if (ics.length > MAX_PROXY_COUNT) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
    
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < ics.length; i++) {
               。。。
            }
    
            // use interface class name list as key.
            String key = sb.toString();
    
            // get cache by class loader.
            final Map<String, Object> cache;
            synchronized (PROXY_CACHE_MAP) {
                cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new HashMap<>());
            }
    
            Proxy proxy = null;
    
            long id = PROXY_CLASS_COUNTER.getAndIncrement();
            String pkg = null;
            ClassGenerator ccp = null, ccm = null;
            try {
                ccp = ClassGenerator.newInstance(cl);
    
                Set<String> worked = new HashSet<>();
                List<Method> methods = new ArrayList<>();
    
                if (pkg == null) {
                    pkg = PACKAGE_NAME;
                }
                。。。
    
                // 最迷惑的一段代码
                // ccp 与 ccm是啥关系【需要看看对应代码怎么写】
                // ccp.toClass 是 org.apache.dubbo.common.bytecode.proxy0类型【小写p】
                // ccm.toClass 是 org.apache.dubbo.common.bytecode.Proxy0类型【大写P】
                // ccp只有定义,但并没有返回或被引用【乍一看】
                // 实际上ccp.toClass 方法就表示 org.apache.dubbo.common.bytecode.proxy0 class已被类加载器加载
                // ccm与ccp 只有 pcn 类名称字符串进行关联 【形式参数】
                // ccm.toClass执行时需要检测pcn【org.apache.dubbo.common.bytecode.proxy0】是否存在
    
                // create ProxyInstance class.
                String pcn = pkg + ".proxy" + id;
                // ccp: org.apache.dubbo.common.bytecode.proxy0
                ccp.setClassName(pcn);
                ccp.addField("public static java.lang.reflect.Method[] methods;");
                ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
                ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
                ccp.addDefaultConstructor();
                Class<?> clazz = ccp.toClass();
                clazz.getField("methods").set(null, methods.toArray(new Method[0]));
    
                // create Proxy class.
                String fcn = Proxy.class.getName() + id;
                ccm = ClassGenerator.newInstance(cl);
                ccm.setClassName(fcn);
                ccm.addDefaultConstructor();
                ccm.setSuperClass(Proxy.class);
                ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
                Class<?> pc = ccm.toClass();
                proxy = (Proxy) pc.newInstance();
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                // release ClassGenerator
                if (ccp != null) {
                    ccp.release();
                }
                if (ccm != null) {
                    ccm.release();
                }
                synchronized (cache) {
                    if (proxy == null) {
                        cache.remove(key);
                    } else {
                        cache.put(key, new WeakReference<Proxy>(proxy));
                    }
                    cache.notifyAll();
                }
            }
            return proxy;
        }
    
        // 创建的代理类需要实现该接口
        // handler:被代理对象
        abstract public Object newInstance(InvocationHandler handler);
    }
    

Proxy创建的动态代理文件 Proxy0.class 【反编译如下】

  • Proxy0 是Proxy的子类,有实现抽象方法:Proxy#newInstance

  • ccm.toClass()生成Proxy0 是需要 proxy0的存在

  • 个人理解:Proxy0可以看作proxy0【接口代理类】的工厂

    /*******调用方代码**********/
    
        @Override
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
            // Proxy.getProxy(interfaces) 返回Proxy0【Proxy的子类】
            // newInstance 则返回 proxy0 【interfaces 实现类】
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }
    /*****************/
    
    // Proxy0 代码
    package org.apache.dubbo.common.bytecode;
    
    import java.lang.reflect.InvocationHandler;
    
    public class Proxy0 extends Proxy implements ClassGenerator.DC {
    
      public Object newInstance(InvocationHandler paramInvocationHandler) {
      // 返回proxy0【interfaces 实现类】
      return new proxy0(paramInvocationHandler);
      }
    }
    

Proxy创建的动态代理文件 proxy0.class【反编译如下】

  • proxy0 持有属性:InvocationHandler

  • InvocationHandler 持有属性:Invoker【被代理类】

  • proxy0是DemoService的实现类

  • 具体方法实现:--> InvocationHandler --> Invoker

    package org.apache.dubbo.common.bytecode;
    
    import com.alibaba.dubbo.rpc.service.EchoService;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.util.Map;
    import java.util.Set;
    import org.apache.dubbo.rpc.protocol.dubbo.support.CustomArgument;
    import org.apache.dubbo.rpc.protocol.dubbo.support.DemoService;
    import org.apache.dubbo.rpc.protocol.dubbo.support.Man;
    import org.apache.dubbo.rpc.protocol.dubbo.support.NonSerialized;
    import org.apache.dubbo.rpc.protocol.dubbo.support.Person;
    import org.apache.dubbo.rpc.protocol.dubbo.support.Type;
    import org.apache.dubbo.rpc.service.Destroyable;
    
    public class proxy0 implements ClassGenerator.DC, Destroyable, DemoService, EchoService {
      public static Method[] methods;
    
      private InvocationHandler handler;
    
      public Object $echo(Object paramObject) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramObject;
        Object object = this.handler.invoke(this, methods[0], arrayOfObject);
        return (Object)object;
      }
    
      public void $destroy() {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[1], arrayOfObject);
      }
    
      public Object invoke(String paramString1, String paramString2) throws Exception {
        Object[] arrayOfObject = new Object[2];
        arrayOfObject[0] = paramString1;
        arrayOfObject[1] = paramString2;
        Object object = this.handler.invoke(this, methods[2], arrayOfObject);
        return (Object)object;
      }
    
      public long add(int paramInt, long paramLong) {
        Object[] arrayOfObject = new Object[2];
        new Integer();
        super(new Integer());
        false[new Integer()] = new Integer();
        new Long();
        super(new Long());
        true[new Long()] = new Long();
        Object object = this.handler.invoke(this, methods[3], arrayOfObject);
        return (object == null) ? false : ((Long)object).longValue();
      }
    
      public String get(CustomArgument paramCustomArgument) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramCustomArgument;
        Object object = this.handler.invoke(this, methods[4], arrayOfObject);
        return (String)object;
      }
    
      public int getInt(int paramInt) {
        Object[] arrayOfObject = new Object[1];
        new Integer();
        super(new Integer());
        false[new Integer()] = new Integer();
        Object object = this.handler.invoke(this, methods[5], arrayOfObject);
        return (object == null) ? 0 : ((Integer)object).intValue();
      }
    
      public long timestamp() {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[6], arrayOfObject);
        return (object == null) ? false : ((Long)object).longValue();
      }
    
      public Set keys(Map paramMap) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramMap;
        Object object = this.handler.invoke(this, methods[7], arrayOfObject);
        return (Set)object;
      }
    
      public Type getType(Type paramType) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramType;
        Object object = this.handler.invoke(this, methods[8], arrayOfObject);
        return (Type)object;
      }
    
      public int getSize(Object[] paramArrayOfObject) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramArrayOfObject;
        Object object = this.handler.invoke(this, methods[9], arrayOfObject);
        return (object == null) ? 0 : ((Integer)object).intValue();
      }
    
      public int getSize(String[] paramArrayOfString) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramArrayOfString;
        Object object = this.handler.invoke(this, methods[10], arrayOfObject);
        return (object == null) ? 0 : ((Integer)object).intValue();
      }
    
      public void sayHello(String paramString) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramString;
        Object object = this.handler.invoke(this, methods[11], arrayOfObject);
      }
    
      public Map echo(Map paramMap) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramMap;
        Object object = this.handler.invoke(this, methods[12], arrayOfObject);
        return (Map)object;
      }
    
      public String echo(String paramString) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramString;
        Object object = this.handler.invoke(this, methods[13], arrayOfObject);
        return (String)object;
      }
    
      public Type enumlength(Type[] paramArrayOfType) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramArrayOfType;
        Object object = this.handler.invoke(this, methods[14], arrayOfObject);
        return (Type)object;
      }
    
      public int stringLength(String paramString) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramString;
        Object object = this.handler.invoke(this, methods[15], arrayOfObject);
        return (object == null) ? 0 : ((Integer)object).intValue();
      }
    
      public void nonSerializedParameter(NonSerialized paramNonSerialized) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramNonSerialized;
        Object object = this.handler.invoke(this, methods[16], arrayOfObject);
      }
    
      public NonSerialized returnNonSerialized() {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[17], arrayOfObject);
        return (NonSerialized)object;
      }
    
      public String getRemoteApplicationName() {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[18], arrayOfObject);
        return (String)object;
      }
    
      public String getPerson(Man paramMan) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramMan;
        Object object = this.handler.invoke(this, methods[19], arrayOfObject);
        return (String)object;
      }
    
      public int getPerson(Person paramPerson1, Person paramPerson2) {
        Object[] arrayOfObject = new Object[2];
        arrayOfObject[0] = paramPerson1;
        arrayOfObject[1] = paramPerson2;
        Object object = this.handler.invoke(this, methods[20], arrayOfObject);
        return (object == null) ? 0 : ((Integer)object).intValue();
      }
    
      public int getPerson(Person paramPerson) {
        Object[] arrayOfObject = new Object[1];
        arrayOfObject[0] = paramPerson;
        Object object = this.handler.invoke(this, methods[21], arrayOfObject);
        return (object == null) ? 0 : ((Integer)object).intValue();
      }
    
      public String getThreadName() {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[22], arrayOfObject);
        return (String)object;
      }
    
      public proxy0() {}
    
      public proxy0(InvocationHandler paramInvocationHandler) { this.handler = paramInvocationHandler; }
    }
    

Wrapper 与 Proxy差异点

  • Wrapper只生成的代理类Wrapper* 【Wrapper子类】
  • Proxy同时生成Proxy*【Proxy子类】,proxy*【接口实现类】
  • Wrapper* 是被代理对象的代理 ,但并不持有被代理对象属性
  • Proxy* 不是被代理对象的代理,但可通过 newInstance方法创建 proxy*
  • proxy* 是被代理对象的代理 ,且持有被代理对象属性
  • 服务调用方必须有通过Proxy创建出对应的proxy*【rpc接口实现类代理】 对象的过程;因为用户代码需要显式调用接口方法
  • wrapper* 没有实现任何接口,所以不能被显式调用,通常在框架内部使用【将任何rpc接口实现类转换成统一对象】进行方法调用;【有例外】