JDK dynamic proxy implementation principle

  • Dynamic Proxy classes are generated using the proxy.newProxyInstance method, as shown in the example from section 1:
/ / create the JDK dynamic Proxy UserService jdkProxy. = (UserService) Proxy newProxyInstance (UserService. Class. GetClassLoader (), new Class[]{UserService.class}, handler);Copy the code
  • Go to proxy. newProxyInstance source code
public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentException Objects.requirenonnull (h); // The interceptor cannot throw an exception for null. // Defensive copying avoids modifying properties of interfaces array objects final Class<? >[] intfs = interfaces.clone(); / / get the Java security manager final SecurityManager sm = System. GetSecurityManager (); // The security manager is not emptyif(sm ! = null) {/ / proxy parameter access checkProxyAccess (Reflection) getCallerClass (), loader, intfs); } // 1. Find or generate proxy Class information: Class<? > cl = getProxyClass0(loader, intfs); try {if(sm ! = null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } // 2. Final Constructor<? > cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; // Set the constructor access permissionif(! Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Voidrun() {
                    cons.setAccessible(true);
                    returnnull; }}); } // 3. Use the constructor to generate the proxy object to set the H interceptor handler into the proxy objectreturn cons.newInstance(new Object[]{h});
    }
Copy the code

We see key code comments 1, 2, and 3. C c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c

  • Enter the source of comment 1 to see how to generate the class information for the proxy class
private static Class<? > getProxyClass0(ClassLoader loader, Class<? >... Interfaces) {// An exception is thrown if the interface array exceeds 65535if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded"); } // If there is a class object for a proxy class that defines and implements the specified interface through the given classloader, the class object is returned. // Create a proxy class object using ProxyClassFactoryreturn proxyClassCache.get(loader, interfaces);
    }
Copy the code

We see that the proxyClassCache. Get method is the key to generating proxy class objects.

  • Go to proxyClassCache. Get to see how to generate the class information of the proxy class
public V get(K key, Subkey Object subkey = objects.requirenonNULL (subkeyFactory.apply (key,)) {// Subkey Object = objects.requirenonNULL (subkeyFactory.apply (key,)); parameter)); Supplier<V> supplier = valuesmap. get(subkey); V value = supplier.get(); // Return the proxy Class objectreturn value;
}
Copy the code

The caching mechanism is used to get the proxy Class object, which is described in more detail in Section 3.

Why must JDK dynamic proxies implement interfaces

  • Because JDK dynamic Proxy classes inherit from Proxy classes, Java is single-inheritance, so the Proxy object can only implement the interface, let the Proxy object generate the implementation of the corresponding interface. So, here’s the problem. Why do JDK dynamic proxies inherit from Proxy classes? Leave it to you to think about!

Dynamic proxy class instance generated by JDK

The dynamic proxy class generated in section 1

public final class $Proxy0 extends Proxy implements UserService {
    private static Method m1;
    private static Method m2;
    private static Method m0;
    private static Method m3;

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

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

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

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

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

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("com.java24k.example.service.UserService").getMethod("addUser"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); }}}Copy the code
  • Any method that calls a dynamic proxy class is the corresponding method that calls the interceptor handler of its parent class.
  • The interceptor handler holds the real object and invokes the corresponding method of the real object in the invoke method of the interceptor handler.