Dynamic Proxy Review

  • Almost all Java-related frameworks require dynamic proxy tools; 【 Personal understanding has the following two points 】
    • Strongly typed: Java is a strongly typed language with type detection at compile time
    • Faceted programming: Before, after user code execution… Weave into common processing logic
  • The JDK dynamic Proxy classes have related Java. Lang. Reflect the Proxy, Java. Lang. Reflect. InvocationHandler
  • To create a Proxy class, the JDK implements the InvocationHandler interface, which is used as a parameter to further create the corresponding Proxy class
  • InvocationHandler: Object invoke(Object Proxy, Method Method, Object[] args) there is only one interface Method, usually we just need to implement the Method, not explicitly called, proxy Object will call this Method
    • Proxy: nested objects such as proxy1 -> proxy2 ->… -> originObject
    • When the proxy object method is called, the InvocationHandler#invoke method is called
  • JDK dynamic proxies require interface definitions; A Javassist or ASM component can have no interface
  • Dynamic proxy related document links

An overview of the

  • Dubbo provides dynamic proxy factories including JdkProxyFactory and JavassistProxyFactory
  • As you can see from the @spi annotation of the ProxyFactory interface, the default implementation is JavassistProxyFactory
  • The core classes for generating Proxy class files using Javassist are Proxy, Wrapper

The role and necessity of dubbo dynamic proxy layer

  • The RPC calls in the figure do not draw serialization, network layer… 【 Abstract 】

  • Proxy-client, proxy-server only refers to the proxy layer in RPC framework. A number of proxy objects can be created

  • The client and server are usually deployed on different servers, so the interface invocation and implementation needs to send network requests

  • When the client invokes the RPC method:

    • You can explicitly call each method of the RPC interface, actually calling the method of the proxy class.
    • Method is usually broken down into classes, method names, parameters, return value types… Data such as
    • Any interface method in proxy is nothing more than className, methodName, paramType, paramValue… Such data;
    • From the specific interface method –> proxy object method –> encapsulation method data is req –> Send REq
  • When the server receives the RPC method request:

    • Parse reQ method data and create corresponding proxy objects;
    • Why not create a concrete RPC interface implementation class object? Framework code can not call the method of the concrete implementation class, can only call the method of Proxy class;
    • Proxy uses reflection to reference concrete implementation classes at user code runtime
    • Receive REq –> parse REQ data –> proxy object –> interface implementation class

Dubbo dynamic proxy

  • ProxyFactory uses JavassistProxyFactory by default

    @SPI("javassist")
    public interface ProxyFactory {
    
        // This method is called more often in the service reference phase.
        // If called in the service reference phase, you usually need to create the corresponding Invoker instance based on the reference RPC interface
        // Create an unnormalized invocation proxy object
        @Adaptive({PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker) throws RpcException;
    
        // This method is called more often in the service reference phase.
        // If called in the service reference phase, you usually need to create the corresponding Invoker instance based on the reference RPC interface
        // generic: controls whether a proxy object is instantiated
        @Adaptive({PROXY_KEY})
        <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException;
    
        // This method is called more often in the service exposure phase.
        // proxy: RPC interface implementation class, or other...
        @Adaptive({PROXY_KEY})
        <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException;
    
    }
    Copy the code
  • JavassistProxyFactory has two core classes, Proxy, Wrapper

  • Note Proxy. GetProxy (interfaces). NewInstance (new InvokerInvocationHandler (invoker)); The return value is not a Proxy type

    public class JavassistProxyFactory extends AbstractProxyFactory {
    
        @Override
        public <T> T getProxy(Invoker
             
               invoker, Class
              [] interfaces)
              {
            Proxy#getProxy returns a Proxy object
            // Pass invoker in newInstance.
            / / [key] to generate specific Proxy objects (concrete Proxy class ClassType not org.apache.dubbo.com mon. The bytecode, Proxy 】
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }
    
        @Override
        public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
            // Create the Wrapper class.
            final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
            // Create the Invoker object, which needs to be passed to proxy [e.g. RPC interface implementation class]
            return new AbstractProxyInvoker<T>(proxy, type, url) {
    
                // Invoke Object (Object proxy, Method Method, Object[] args)
                @Override
                protected Object doInvoke(T proxy, String methodName, Class
             [] parameterTypes, Object[] arguments) throws Throwable {
                    // AbstractProxyInvoker#invoke calls the doInvoke method
                    // the doInvoke method calls wrapper#invokeMethod
                    // the wrapper#invokeMethod method calls the corresponding proxy method
                    returnwrapper.invokeMethod(proxy, methodName, parameterTypes, arguments); }}; }}Copy the code

Dubbo Wrapper proxy class creation analysis

  • The testDemoProtocol method requires invoker to execute the protocol.export(invoker) method

  • This invoker is created using proxyFactory.getInvoker(***).

  • The JavassistProxyFactory#getInvoker method is called by default; Call the Wrapper-related methods further

    public class DubboProtocolTest {
        private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
        private ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    
        @Test
        public void testDemoProtocol(a) throws Exception {
            // Interface implementation object
            DemoService service = new DemoServiceImpl();
            int port = NetUtils.getAvailablePort();
            // Parsing entry: service exposure phase call Proxy#getInvoker [with exceptions]
            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); }... }Copy the code

org.apache.dubbo.common.bytecode.Wrapper

  • Proxy.getinvoker (***) executes the Wrapper#getWrapper method

  • Wrapper#makeWrapper primarily calls the javassist API to generate dynamic proxy classes

  • Debug to cc.toclass () manually run cc.mctc.writefile (“/doc”); You will see the Wrapper*.class file in the /doc/** directory

    public abstract class Wrapper {
        private static finalMap<Class<? >, Wrapper> WRAPPER_MAP =newConcurrentHashMap<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);
    
        // The argument object Class here is usually the Class of the propped object
        public static Wrapper getWrapper(Class
              c) {
           // If the proxy type is already dynamic
            while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
            {
                c = c.getSuperclass();
            }
    
            if (c == Object.class) {
                return OBJECT_WRAPPER;
            }
            // There will be a cache
            return WRAPPER_MAP.computeIfAbsent(c, key -> makeWrapper(key));
        }
    
        // Create the dynamic proxy Wrapper class
        // Call the Javassist utility class to generate a class file. This method is very long.
        // Those interested in the Javassist API can read the source code
        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);
            // Dynamic proxy class names are usually Wrapper0, Wrapper1...
            // The dynamic proxy class is in the same package as the Wrapper
            cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
            // The dynamic proxy class extends Wrapper
            cc.setSuperClass(Wrapper.class);
    
            try {
                // Generate the Class Class
                // debug to run cc.mctc.writefile ("/doc"); Can generate dynamic proxy class file decompilation can see the corresponding codeClass<? > 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()); Will implement this class
        // instance
        abstract public Object invokeMethod(Object instance, String mn, Class
             [] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
    }
    Copy the code

Dynamic proxy file wrapper0.class created from Wrapper

  • Wrapper0 is a class generated by calling wrapper.getwrapper (DemoServicePl.class). This method is usually called during service exposure to uniformly convert all RPC interface implementation classes into subclasses of Wrapper.

  • Within each method in Wrapper0, there is a line of code that converts the parameter to type DemoServiceImpl

  • In the proxy class instance [e.g., Wrapper0] and proxy class instance creation phase only need to pass in the class type of the proxied object; [Formal parameters]

  • Wrapper0#invokeMethod (); Wrapper0#invokeMethod

  • Wrapper0 does not have the proxied object instance as an attribute; A Proxy generates a Proxy object that has instances of the proxied object as properties

    // In the same package as the Wrapper
    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;
    
    // Implement the classGenerator. DC interface to indicate that Wrapper0 is a dynamic proxy class
    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.");
      }
    
      // All DemoService method call entries
      public Object invokeMethod(Object paramObject, String paramString, Class[] paramArrayOfClass, Object[] paramArrayOfObject) throws InvocationTargetException {
        // Execute to wrapper.getwrapper (demoServiceImpl.class);
        // All methods in Wrapper0 call the demoServiceImpl method internally
        DemoServiceImpl demoServiceImpl;
        try {
          demoServiceImpl = (DemoServiceImpl)paramObject;
        } catch (Throwable throwable) {
          throw new IllegalArgumentException(throwable);
        } 
        // See this string if else also slightly drunk
        // All methods of the DemoService interface are in the following method names
        // The options are EchoService and Destroyable
        // AbstractProxyFactory has code to add *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 newInvocationTargetException(throwable); }}}Copy the code

Dubbo Proxy Proxy class creation analysis

  • The testDemoProtocol method calls protocol.refer(***) to generate the Invoke object

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

  • Invoke is called proxyFactory.getProxy(invoke) as a proxied object to generate a proxy object.

  • Proxy.getproxy (interfaces) returns a subclass of Proxy,

  • NewInstance (New InvokerInvocationHandler(invoker)); The return value is the implementation class of the concrete interface

    public class DubboProtocolTest {
        private Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
        private ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
    
        @Test
        public void testDemoProtocol(a) 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")));
            // analysis entry: proxyFactory#getProxy is invoked in the service reference phase.
            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); }... }Copy the code

org.apache.dubbo.common.bytecode.Proxy

  • Entry method: Proxy#getProxy

  • Proxy also uses Javassist to generate Proxy objects

  • Proxy# getProxy call mon org.apache.dubbo.com. There are two times in the bytecode. ClassGenerator# toClass (); Ccp.toclass (); and ccm.toclass ();

  • Calling toClass twice is one of the easier areas to confuse the reader

  • Pay attention to the CCP. ToClass is org.apache.dubbo.com mon. The bytecode. Proxy0 type “lowercase p”

  • Note that CCM toClass is org.apache.dubbo.com mon. The bytecode. Proxy0 type [uppercase P]

  • Debug toClass manually execute ccm.mctc.writefile (“/doc”); ccp.mCtc.writeFile(“/doc”); The corresponding class file can be generated

    public abstract class Proxy {
    
        private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
        private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
        // The proxy generates the cache
        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(a) {}.../**
         * 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; }...// The most confusing piece of code
                // what is the relationship between CCP and CCM
                / / CCP. Mon toClass is org.apache.dubbo.com. The bytecode. Proxy0 type "lowercase p"
                / / CCM. Mon toClass is org.apache.dubbo.com. The bytecode. Proxy0 type [uppercase P]
                // CCP only has definitions, but is not returned or referenced.
                / / CCP. Actually means org.apache.dubbo.com mon toClass method. The bytecode. Proxy0 class has been the class loader loads
                CCM and CCP are only associated with the PCN class name string.
                / / CCM. ToClass executes the PCN to check the org.apache.dubbo.com mon. The bytecode. Proxy0 】 exists
    
                // 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, newClass<? >[]{InvocationHandler.class},newClass<? > [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, newWeakReference<Proxy>(proxy)); } cache.notifyAll(); }}return proxy;
        }
    
        // Create a proxy class that implements this interface
        // handler: proxied object
        abstract public Object newInstance(InvocationHandler handler);
    }
    Copy the code

Create dynamic Proxy file proxy0.class

  • Proxy0 is a subclass of Proxy with an abstract implementation method: Proxy#newInstance

  • Ccm.toclass () generates Proxy0 by requiring the presence of Proxy0

  • Proxy0 can be seen as a factory for Proxy0

    /******* caller code **********/
    
        @Override
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Invoker
             
               invoker, Class
              [] interfaces)
              {
            // proxy.getProxy (interfaces) returns Proxy0
            // interfaces will return proxy0
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }
    / * * * * * * * * * * * * * * * * * /
    
    / / Proxy0 code
    package org.apache.dubbo.common.bytecode;
    
    import java.lang.reflect.InvocationHandler;
    
    public class Proxy0 extends Proxy implements ClassGenerator.DC {
    
      public Object newInstance(InvocationHandler paramInvocationHandler) {
      // return proxy0 [interfaces]
      return newproxy0(paramInvocationHandler); }}Copy the code

Create dynamic Proxy file proxy0.class

  • Proxy0 holds the attribute InvocationHandler

  • InvocationHandler holds the Invoker attribute.

  • Proxy0 is the implementation class of 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(a) {
        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(a) {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[17], arrayOfObject);
        return (NonSerialized)object;
      }
    
      public String getRemoteApplicationName(a) {
        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(a) {
        Object[] arrayOfObject = new Object[0];
        Object object = this.handler.invoke(this, methods[22], arrayOfObject);
        return (String)object;
      }
    
      public proxy0(a) {}
    
      public proxy0(InvocationHandler paramInvocationHandler) { this.handler = paramInvocationHandler; }}Copy the code

Wrapper and Proxy differences

  • Wrapper only generated proxy class Wrapper*
  • Proxy generates a Proxy* [Proxy subclass], Proxy* [interface implementation class]
  • Wrapper* is a proxy for the proxied object, but does not hold properties of the proxied object
  • Proxy* is not a Proxy for the propped object, but can be created using the newInstance method
  • Proxy * is the proxy of the proxied object and holds the properties of the proxied object
  • The service caller must have a process to create the corresponding Proxy * [RPC interface implementation class Proxy] object through Proxy; Because the user code needs to explicitly call the interface methods
  • Wrapper * does not implement any interface and therefore cannot be explicitly called, usually within the framework using a method call to convert any RPC interface implementation class into a unified object. [With exceptions]