Java dynamic proxy function and source code analysis


1. Understanding

  • Static proxy: Static proxy is to manually complete the interface, implementation class, and proxy class at compile time
  • Dynamic proxy: dynamically create proxy classes and their instances as needed during program running to complete specific functions

2. Application scenarios

  • Refer to the decorator pattern and re-encapsulate the existing methods to implement new functions
  • AOP Aspect-Oriented Programming Ideas

3. Implementation code

Before understanding dynamic proxy, let's see how static proxy is implemented through the simplest example.
First define an interface

package about_proxy.static_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public interface Subject {

    public void doSomething();

}

Complete an implementation class of this interface and implement the doSomething method

package about_proxy.static_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public class RealSubject implements Subject {

    @Override
    public void doSomething() {

        System.out.println("call doSomething()");

    }
}

If there is a demand at this time, you need to rewrite the doSomething method, add the log printing function before and after the method is executed, and calculate the time-consuming of this function, but the implementation logic is complicated < It seems not complicated, only one sentence is printed, don't care about these details. >, do not want to modify the original code, then we create a new proxy class in which to implement the functions we need.

package about_proxy.static_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public class SubjectProxy implements Subject {

    Subject subimpl = new RealSubject();

    @Override
    public void doSomething() {
        System.out.println("我们先做点什么");
        subimpl.doSomething();
        System.out.println("我们再做点什么");

    }
}

At this time, we can use the new proxy class to implement new requirements without modifying the source code. Complete the test class below

package about_proxy.static_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public class TestStaticProxy {

    public static void main(String args[]) {
//        Subject sub = new RealSubject();
        Subject sub = new SubjectProxy();
        sub.doSomething();
    }
}

Well, at this time we have completed the requirements of the demand personnel. But at this time, the boss jumped out again and said that I wanted to test the time consumption of methods in multiple classes in the project.
Dry! How many new proxy classes should I create?
At this time, dynamic proxy came into being. First we define the interface

package about_proxy.dynamic_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public interface Subject {
    public void doSomething();
}

Then define the implementation class

package about_proxy.dynamic_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("call doSomething()");
    }
}

We have completed the preparations above, and then implement dynamic proxy

package about_proxy.dynamic_proxy;

import org.omg.CORBA.portable.InvokeHandler;
import sun.rmi.runtime.Log;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public class ProxyHandler implements InvocationHandler {

    private Object tar;


    public Object bind(Object tar)
    {
        this.tar = tar;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);
    }



    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result = null;
        //这里就可以进行所谓的AOP编程了
        //在调用具体函数方法前,执行功能处理
        System.out.println("start time:"+System.currentTimeMillis());
        result = method.invoke(tar,args);
        //在调用具体函数方法后,执行功能处理
        System.out.println("end time:"+System.currentTimeMillis());
        return result;

    }
}

Finally, use dynamic proxy in the test class

package about_proxy.dynamic_proxy;

/**
 * Created by solie_h on 2018/2/7.
 */
public class TestDynamicProxy {

    public static void main(String args[]){
//        Subject sub = new RealSubject();
        ProxyHandler proxy = new ProxyHandler();
        //绑定该类实现的所有接口
        Subject sub = (Subject) proxy.bind(new RealSubject());
        sub.doSomething();
    }
}

In this way, we can implement the functions of multiple proxy classes in one ProxyHandler (only one dynamic proxy is used in this demo), but only one entity class is created. How is it achieved? The dynamic proxy actually generates multiple proxy classes dynamically for us during operation. Let's use the source code to understand how it operates in jdk.

Fourth, the principle analysis

We can debug the demo. When the project executes to the doSomething() method, it enters the invoke method in the ProxyHandler class, so that we can add the functions we want before and after the real doSomething() method.
Why enter into invoke?
The bind method of ProxyHandler is called in the main method of the above demo,

Subject sub = (Subject) proxy.bind(new RealSubject());

In fact, the static method newProxyInstance() of the Proxy class is called

Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this);

Here is the key to generating the agent, we continue to follow up to see the internal key

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, 
InvocationHandler h) throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * 获取代理类。
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * 使用指定的invocationHandler调用构造方法
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }
            //调用代理对象的构造函数(代理对象的构造函数$Proxy0(InvocationHandler h),通过字节码反编译可以查看生成的代理类)  
            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            //生成代理类的实例,并把MyInvocationHander的实例作为构造函数参数传入  
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

Let's continue to see how to get the proxy class and follow the Class<?> cl = getProxyClass0(loader, intfs) method

   /**
    * Generate a proxy class.  Must call the checkProxyAccess method
    * to perform permission checks before calling this.
    */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        //实现接口的最大数量<65535
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        //调用了get方法
        return proxyClassCache.get(loader, interfaces);
    }

Continue to follow proxyClassCache.get(loader, interfaces);

    /**
     * @param key       上面传入的loader,类加载器
     * @param parameter 上面方法传入的interfaces,接口数组
     */
    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);

        expungeStaleEntries();

        Object cacheKey = CacheKey.valueOf(key, refQueue);

        // lazily install the 2nd level valuesMap for the particular cacheKey
        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
        if (valuesMap == null) {
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        Supplier<V> supplier = valuesMap.get(subKey);
        Factory factory = null;

        while (true) {
            if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                // 返回的value是通过该方法调用的
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
            }
            // else no supplier in cache
            // or a supplier that returned null (could be a cleared CacheValue
            // or a Factory that wasn't successful in installing the CacheValue)

            // lazily construct a Factory
            if (factory == null) {
                factory = new Factory(key, parameter, subKey, valuesMap);
            }

            if (supplier == null) {
                supplier = valuesMap.putIfAbsent(subKey, factory);
                if (supplier == null) {
                    // successfully installed Factory
                    supplier = factory;
                }
                // else retry with winning supplier
            } else {
                if (valuesMap.replace(subKey, supplier, factory)) {
                    // successfully replaced
                    // cleared CacheEntry / unsuccessful Factory
                    // with our Factory
                    supplier = factory;
                } else {
                    // retry with current supplier
                    supplier = valuesMap.get(subKey);
                }
            }
        }
    }

We continue to look at the supplier.get() method, which is implemented in the inner class Factory of WeakCache. The code is as follows

        @Override
        public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
                // 这里又通过valueFactory.apply(key, parameter)得到value进行返回
                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
            } finally {
                if (value == null) { // remove us on failure
                    valuesMap.remove(subKey, this);
                }
            }
            // the only path to reach here is with non-null value
            assert value != null;

            // wrap value with CacheValue (WeakReference)
            CacheValue<V> cacheValue = new CacheValue<>(value);

            // try replacing us with CacheValue (this should always succeed)
            if (valuesMap.replace(subKey, this, cacheValue)) {
                // put also in reverseMap
                reverseMap.put(cacheValue, Boolean.TRUE);
            } else {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            return value;
        }
    }

Continue to track the valueFactory.apply(key, parameter) method, which is implemented in Proxy's inner class ProxyClassFactory

@Override
        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {

            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
            for (Class<?> intf : interfaces) {
                /*
                 * 确保该loader加载的此类(intf)
                 */
                Class<?> interfaceClass = null;
                try {
                    interfaceClass = Class.forName(intf.getName(), false, loader);
                } catch (ClassNotFoundException e) {
                }
                if (interfaceClass != intf) {
                    throw new IllegalArgumentException(
                        intf + " is not visible from class loader");
                }
                /*
                 * 确保是一个接口
                 */
                if (!interfaceClass.isInterface()) {
                    throw new IllegalArgumentException(
                        interfaceClass.getName() + " is not an interface");
                }
                /*
                 * 确保接口没重复
                 */
                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                    throw new IllegalArgumentException(
                        "repeated interface: " + interfaceClass.getName());
                }
            }

            String proxyPkg = null;     // package to define proxy class in
            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

            /*
             * 验证所有非公共的接口在同一个包内;公共的就无需处理.
             */
            for (Class<?> intf : interfaces) {
                int flags = intf.getModifiers();
                if (!Modifier.isPublic(flags)) {
                    accessFlags = Modifier.FINAL;
                    String name = intf.getName();
                    int n = name.lastIndexOf('.');
                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                    if (proxyPkg == null) {
                        proxyPkg = pkg;
                    } else if (!pkg.equals(proxyPkg)) {
                        throw new IllegalArgumentException(
                            "non-public interfaces from different packages");
                    }
                }
            }

            if (proxyPkg == null) {
                // if no non-public proxy interfaces, use com.sun.proxy package
                proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
            }

            /*
             * 为代理类生成一个名字,防止重复
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * 具体生成代理类的方法又在该方法中实现
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
        }
    }

再跟踪ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags)

public static byte[] generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags) {
        ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
        //真正生成字节码的方法
        final byte[] classFile = gen.generateClassFile();
        //如果saveGeneratedFiles为true 则生成字节码文件,所以在开始我们要设置这个参数
        //当然,也可以通过返回的bytes自己输出
        if (saveGeneratedFiles) {
            java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() {
                public Void run() {
                    try {
                        int i = name.lastIndexOf('.');
                        Path path;
                        if (i > 0) {
                            Path dir = Paths.get(name.substring(0, i).replace('.', File.separatorChar));
                            Files.createDirectories(dir);
                            path = dir.resolve(name.substring(i+1, name.length()) + ".class");
                        } else {
                            path = Paths.get(name + ".class");
                        }
                        Files.write(path, classFile);
                        return null;
                    } catch (IOException e) {
                        throw new InternalError( "I/O exception saving generated file: " + e);
                    }
                }
            });
        }
        return classFile;
    }

Continue to generate your own code, here is the final generation method

private byte[] generateClassFile() {
  /* ============================================================
   * Step 1: Assemble ProxyMethod objects for all methods to generate proxy dispatching code for.
   * 步骤1:为所有方法生成代理调度代码,将代理方法对象集合起来。
   */
  //增加 hashcode、equals、toString方法
  addProxyMethod(hashCodeMethod, Object.class);
  addProxyMethod(equalsMethod, Object.class);
  addProxyMethod(toStringMethod, Object.class);
  //增加接口方法
  for (Class<?> intf : interfaces) {
   for (Method m : intf.getMethods()) {
    addProxyMethod(m, intf);
   }
  }

  /*
   * 验证方法签名相同的一组方法,返回值类型是否相同;意思就是重写方法要方法签名和返回值一样
   */
  for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
   checkReturnTypes(sigmethods);
  }

  /* ============================================================
   * Step 2: Assemble FieldInfo and MethodInfo structs for all of fields and methods in the class we are generating.
   * 为类中的方法生成字段信息和方法信息
   */
  try {
   //增加构造方法
   methods.add(generateConstructor());
   for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
    for (ProxyMethod pm : sigmethods) {
     // add static field for method's Method object
     fields.add(new FieldInfo(pm.methodFieldName,
       "Ljava/lang/reflect/Method;",
       ACC_PRIVATE | ACC_STATIC));
     // generate code for proxy method and add it
     methods.add(pm.generateMethod());
    }
   }
   //增加静态初始化信息
   methods.add(generateStaticInitializer());
  } catch (IOException e) {
   throw new InternalError("unexpected I/O Exception", e);
  }

  if (methods.size() > 65535) {
   throw new IllegalArgumentException("method limit exceeded");
  }
  if (fields.size() > 65535) {
   throw new IllegalArgumentException("field limit exceeded");
  }

  /* ============================================================
   * Step 3: Write the final class file.
   * 步骤3:编写最终类文件
   */
  /*
   * Make sure that constant pool indexes are reserved for the following items before starting to write the final class file.
   * 在开始编写最终类文件之前,确保为下面的项目保留常量池索引。
   */
  cp.getClass(dotToSlash(className));
  cp.getClass(superclassName);
  for (Class<?> intf: interfaces) {
   cp.getClass(dotToSlash(intf.getName()));
  }

  /*
   * Disallow new constant pool additions beyond this point, since we are about to write the final constant pool table.
   * 设置只读,在这之前不允许在常量池中增加信息,因为要写常量池表
   */
  cp.setReadOnly();

  ByteArrayOutputStream bout = new ByteArrayOutputStream();
  DataOutputStream dout = new DataOutputStream(bout);

  try {
   // u4 magic;
   dout.writeInt(0xCAFEBABE);
   // u2 次要版本;
   dout.writeShort(CLASSFILE_MINOR_VERSION);
   // u2 主版本
   dout.writeShort(CLASSFILE_MAJOR_VERSION);

   cp.write(dout);    // (write constant pool)

   // u2 访问标识;
   dout.writeShort(accessFlags);
   // u2 本类名;
   dout.writeShort(cp.getClass(dotToSlash(className)));
   // u2 父类名;
   dout.writeShort(cp.getClass(superclassName));
   // u2 接口;
   dout.writeShort(interfaces.length);
   // u2 interfaces[interfaces_count];
   for (Class<?> intf : interfaces) {
    dout.writeShort(cp.getClass(
      dotToSlash(intf.getName())));
   }
   // u2 字段;
   dout.writeShort(fields.size());
   // field_info fields[fields_count];
   for (FieldInfo f : fields) {
    f.write(dout);
   }
   // u2 方法;
   dout.writeShort(methods.size());
   // method_info methods[methods_count];
   for (MethodInfo m : methods) {
    m.write(dout);
   }
   // u2 类文件属性:对于代理类来说没有类文件属性;
   dout.writeShort(0); // (no ClassFile attributes for proxy classes)

  } catch (IOException e) {
   throw new InternalError("unexpected I/O Exception", e);
  }

  return bout.toByteArray();
 }

After analyzing the source code above, we will print the proxy class dynamically generated by Proxy.newProxyInstance(tar.getClass().getClassLoader(), tar.getClass().getInterfaces(), this) in the bind method called in the demo Come out and modify our demo

package about_proxy.dynamic_proxy;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by solie_h on 2018/2/7.
 */
public class TestDynamicProxy {

    public static void main(String args[]){
//        Subject sub = new RealSubject();
        ProxyHandler proxy = new ProxyHandler();
        //绑定该类实现的所有接口
        Subject sub = (Subject) proxy.bind(new RealSubject());
        // 将动态生成的代理类打印出来
        // 这里需要修改为你需要输出的路径
        String path = "请修改路径/TestProxy.class";
        byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",RealSubject.class.getInterfaces());
        FileOutputStream out = null;

        try {
            out = new FileOutputStream(path);
            out.write(classFile);
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        sub.doSomething();

    }

}

Decompile the generated TestProxy.class file, here is an online decompilation tool for students who are not familiar with decompilation operations : http://www.javadecompilers.com/

import about_proxy.dynamic_proxy.Subject;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
  extends Proxy
  implements Subject
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final void doSomething()
  {
    try
    {
      h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("about_proxy.dynamic_proxy.Subject").getMethod("doSomething", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

Let's first look at the constructor of this class

 public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }

The incoming parameter is InvocationHandler, which is why the dynamic proxy class will go to the invoke method in the custom InvocationHandler when calling the method in the interface.
super(paramInvocationHandler) is the constructor that calls the parent class Proxy. The parent class holds an instance of protected InvocationHandler h, refer to the constructor of Proxy:

  protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
        this.h = h;
    }

Continue to look at the static code block of the decompiled file

static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("about_proxy.dynamic_proxy.Subject").getMethod("doSomething", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }

The name of the method doSomething we defined in the interface is m3 through reflection, and we continue to look at the doSomething() method implemented in the file

  public final void doSomething()
  {
    try
    {
      h.invoke(this, m3, null);
      return;
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

Here, the doSomething method of the proxy object is called, and the invoke method in the InvocationHandler is called directly, and m3 is passed in.
this.h.invoke(this, m3, null);
the same is true for the rest of equals, toString, hashCode.
It is very clear here, and all the dynamic proxy processes are also clear.

V. Summary

The JDK dynamically generates proxy classes, and by calling the parser, the principle of executing the methods implemented by the interface is clear at a glance. Dynamic proxies plus reflection are the foundation of many frameworks. Looking forward to the next chapter to implement the principle analysis of android's injection framework based on dynamic proxy and reflection.



Author: solie_h
Link: https://www.jianshu.com/p/9d5ef621f2d1
Source: Jianshu The
copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325522303&siteId=291194637