Brief analysis of dynamic proxy

proxy mode

  • An abstract interface, a functional class, and a proxy class of a functional class. Agent classes combine functional classes. Both functional classes and proxies of functional classes implement abstract interfaces. The caller calls the actual function class through the proxy class.
  • Agents are divided into static agents and dynamic agents. Classic use of dynamic proxy: Retrofitopen source library.
  • 1. The difference from the adapter mode: the adapter mode mainly changes the interface of the object under consideration, while the proxy mode cannot change the interface of the proxy class.
    2. The difference between the decorator mode and the decorator mode: the decorator mode is to enhance the function, while the proxy mode is to control it.
  • Application scenarios: remote agent (server and client), security agent (security control), virtual agent, lazy loading, intelligent guidance.

Please add image description

dynamic proxy

Dynamic proxy implementation process

  1. Customize an interface interface. Dynamic proxies can only proxy interfaces, because the proxy class inherits the Proxy class.
  2. Customize Handlerclasses, extend implementation InvocationHandlerinterfaces, and implement invokemethods.
  3. By Proxy.newProxyInstanceobtaining a dynamic proxy class instance proxy. The first parameter is the classLoader of the interface, the second parameter is the class of the interface, and the third parameter is the object instance of step 2.
  4. proxyIt implements the interface interface, and you can call the interface method. At this time, the method of calling the interface will eventually call the method InvocationHandlerin step 2 invoke.

Roles in dynamic proxies

  • interface is an abstract interface in the proxy pattern.
  • InvocationHandlerIs the role of the actual functional class (RealClass) in the proxy pattern.
  • Proxy.newProxyInstanceInside the function, a proxy class will be generated in the JVM, that is, the proxy class ProxyClass in the proxy mode; the function return result is an instance object of the proxy class, which is equivalent to the one in the client proxyClassObject.

Get the Proxy proxy class.

  • getProxyClass(ClassLoader loader, Class<?>... interfaces)Get the proxy class class type. You can use this class type to reflect the constructor and create an instance.

newProxyInstance method analysis

  1. Generate proxy class. getProxyClass0Generate proxy classes through methods. This function can generate a $Proxy0.classfile and load it into the JVM as a proxy class.
  2. Obtain the proxy class constructor through reflection. The input parameters of the constructor are InvocationHandler.
  3. Generate proxy class instances through the constructor.
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
    throws IllegalArgumentException
{
    
    
    Objects.requireNonNull(h);
    final Class<?>[] intfs = interfaces.clone();
    // 省略......
    /*
     * Look up or generate the designated proxy class.
     */
    Class<?> cl = getProxyClass0(loader, intfs); // 步骤1。核心步骤,生成class类,并让JVM加载。

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
    
    
        // 省略......
        final Constructor<?> cons = cl.getConstructor(constructorParams); // 步骤2 获取构造函数
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
    
    
            cons.setAccessible(true);
        }
        return cons.newInstance(new Object[]{
    
    h}); // 步骤3 new 一个代理类实例
    } catch (IllegalAccessException|InstantiationException e) {
    
    
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
    
    
        // 省略......
    } catch (NoSuchMethodException e) {
    
    
        throw new InternalError(e.toString(), e);
    }
}

Implementation of getProxyClass0 function in standard JVM virtual machine

  • The core implementation of generating dynamic classes is Proxy.ProxyClassFactory#applymethods. Call ProxyGenerator.generateProxyClass(final String name, Class<?>[] interfaces, int accessFlags)method.
  • generateProxyClassThe principle is probably to parse the methods defined in the interface, and then $Proxy0.classgenerate a class file through character splicing or writing a file (file name), load it into the JVM, and generate a proxy class.
  • ProxyGeneratorClass source code link: https://github.com/JetBrains/jdk8u_jdk/blob/master/src/share/classes/sun/misc/ProxyGenerator.java
  • Proxy class generated by the system. The code below $Proxy0is not actually decompiled from the dynamic proxy class file generated by jvm, but refers to other bloggers' articles and roughly wrote it to facilitate understanding of the proxy class generated by the system.
// 自定义一个接口
public interface NameInterface {
    
    
    String getName();
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

 // 这个类不是实际反编译的类,和实际系统生成的类有出入
 // 反编译类继承了Proxy类(动态代理只能代理接口),并且实现了抽象接口。
public final class $Proxy0 extends Proxy implements NameInterface {
    
    
    private static Method m1;
    private static Method m3; //m3代表接口方法,静态块中赋值
    private static Method m2;
    private static Method m0;

    // java.lang.reflect.Proxy#Proxy(java.lang.reflect.InvocationHandler)
    // 父类Proxy组合了一个InvocationHandler对象
    public $Proxy0(InvocationHandler paramInvocationHandler) throws {
    
    
        super(paramInvocationHandler);
    }

    static {
    
    
        try {
    
    
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{
    
    Class.forName("java.lang.Object")});
            m3 = Class.forName("NameInterface").getMethod("getName", new Class[0]); // 反射了接口Method,作为invoke函数的入参
            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());
        }
    }

    @Override
    public String getName() throws {
    
    
        try {
    
    
            return (String) this.h.invoke(this, m3, null); // 调用InvocationHandler的invoke方法
        } catch (Error | RuntimeException localError) {
    
    
            throw localError;
        } catch (Throwable localThrowable) {
    
    
            throw new UndeclaredThrowableException(localThrowable);
        }
    }
    // 还有其他的equals、hashcode、toString方法。
}

Implementation of getProxyClass0 function in Android virtual machine

  • Core implementation: The core implementation of generating dynamic classes is Proxy.ProxyClassFactory#applymethods. Call the native method Proxy#generateProxyto generate a proxy class.
/**
 * A factory function that generates, defines and returns the proxy class given
 * the ClassLoader and array of interfaces.
 */
private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
    
    
    // prefix for all proxy class names
    private static final String proxyClassNamePrefix = "$Proxy";

    // next number to use for generation of unique proxy class names
    private static final AtomicLong nextUniqueNumber = new AtomicLong();

    @Override
    public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
    
        //省略部分代码.....   for循环校验interfaces 合法性
        //省略部分代码..... for循环遍历非public的接口类,确保所有非public接口是同包名下的
        {
    
    
            // Android-changed: Generate the proxy directly instead of calling
            // through to ProxyGenerator.
            List<Method> methods = getMethods(interfaces);
            Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
            validateReturnTypes(methods);
            List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);

            Method[] methodsArray = methods.toArray(new Method[methods.size()]);
            Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);

            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num; //包名 + 类名 + 数字

            return generateProxy(proxyName, interfaces, loader, methodsArray, exceptionsArray);
        }
    }
}
  • Function flow: Proxy#getProxyClass0-> WeakCache#get-> WeakCache.Factory#Factory-> WeakCache.Factory#get-> Proxy.ProxyClassFactory#apply-> Proxy#generateProxy-> native methodProxy_generateProxy
  • WeakCache#subKeyFactoryThe type is Proxy.KeyFactory; WeakCache#valueFactorythe type is Proxy.ProxyClassFactory; WeakCache.Factoryinherited function.Supplier;
// java.lang.reflect.Proxy
/**
 * a cache of proxy classes
 */
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
    proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
  • generateProxyNative implements Android system source code: art/runtime/native/java_lang_reflect_Proxy.cc
static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
                                  jobject loader, jobjectArray methods, jobjectArray throws) {
    
    
  ScopedFastNativeObjectAccess soa(env);
  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
  return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
      soa, name, interfaces, loader, methods, throws));
}
// JNI动态注册
static JNINativeMethod gMethods[] = {
    
    
  FAST_NATIVE_METHOD(Proxy, generateProxy, "(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
};

void register_java_lang_reflect_Proxy(JNIEnv* env) {
    
    
  REGISTER_NATIVE_METHODS("java/lang/reflect/Proxy");
}
  • As defined in the art/runtime/class_linker.cc source code file ClassLinker::CreateProxyClass, this method is the core method for Android to generate class proxy classes.
mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
                                             jstring name,
                                             jobjectArray interfaces,
                                             jobject loader,
                                             jobjectArray methods,
                                             jobjectArray throws)

Guess you like

Origin blog.csdn.net/followYouself/article/details/120242621