This article is original, please indicate the source

This article assumes that you already know how to play JDK dynamic proxy, if not, please go to: juejin.cn/post/686518…

We define and proxy some classes according to the flow of dynamic proxy:

Customize a dynamic proxy

// Define the proxied interface
public interface Person {
    String getName(a);
}

// Define the implementation class of the interface
public class Man implements Person {
    @Override
    public String getName(a) {
        return "man"; }}// Define dynamic proxy
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PersonProxy implements InvocationHandler {

    private Person person;

    public PersonProxy(Person person) {
        this.person = person;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        returnmethod.invoke(person, args); }}/** ** finally calls */ here
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        System.out.println(Boolean.getBoolean("jdk.proxy.ProxyGenerator.saveGeneratedFiles"));

        // This line defines the need to save the dynamically generated class to a file
        System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles"."true");
        System.out.println(Boolean.getBoolean("jdk.proxy.ProxyGenerator.saveGeneratedFiles"));

        Person p = (Person) Proxy.newProxyInstance(Main.class.getClassLoader(), new Class[]{Person.class}, new PersonProxy(new Man()));

        Class<?> cla = p.getClass();
        System.out.println(cla);
    }
}
Copy the code

Need the way, here to save the dynamic proxy class files generated setting method, you can refer to: Java. Lang. Reflect. ProxyGenerator in this line of code:

/** * debugging flag for saving generated class files */
    private static final boolean saveGeneratedFiles =
            java.security.AccessController.doPrivileged(
                    new GetBooleanAction(
                            "jdk.proxy.ProxyGenerator.saveGeneratedFiles"));
Copy the code

The JDK. Proxy. ProxyGenerator. SaveGeneratedFiles system variable is set to true after dynamically generated bytecode file can be kept.

Dynamic proxy core code:

In the java.lang.reflect.Proxy class, the core code to generate the Proxy class is as follows (based on JDK14):

/* * Generate the specified proxy class. * PROXY_GENERATOR_V49 specifies whether the proxy class is below JDK1.5
byte[] proxyClassFile = PROXY_GENERATOR_V49
        ? ProxyGenerator_v49.generateProxyClass(proxyName, interfaces, accessFlags)
        : ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
try{ Class<? > pc = JLA.defineClass(loader, proxyName, proxyClassFile,null."__dynamic_proxy__");
    reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
    return pc;
} catch (ClassFormatError e) {
    throw new IllegalArgumentException(e.toString());
}
Copy the code

As you can see, ProxyGenerator generates a byte array of class objects, which is the actual Java bytecode, a.class file. Finally loaded in via JLA.

Decompile the generated class

$Proxy0. Class = $Proxy0. Class = $Proxy0. Class = $Proxy0.

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

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

* inherits from Proxy and ADAPTS to Person via an adapter-like pattern, so you can cast to Person */
public final class $Proxy0 extends Proxy implements Person {
    private static Method m0;
    private static Method m1;
    private static Method m2;
    private static Method m3;

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

    public final int hashCode(a) {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}public final boolean equals(Object var1) {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}public final String toString(a) {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}/** * The dynamically generated getName method actually calls the PersonProxy invoke method */
    public final String getName(a) {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw newUndeclaredThrowableException(var3); }}static {
        try {
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("test.Person").getMethod("getName");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw newNoClassDefFoundError(var3.getMessage()); }}}Copy the code

By decomcompiling the code above, you can see that the generated class inherits from Proxy and ADAPTS to our own interface through the adapter pattern, which is why JDK dynamic proxies can only Proxy interfaces:

Because Java cannot inherit from multiple classes, it can only inherit from multiple interfaces

By adapting our own interface, we can cast to the object we want. When making a method call, we actually invoke the Invoke method from our own implementation of the proxy.

If you have any questions, please leave a comment below