How to view the $ProxyX.class file in Proxy mode

When learning the implementation principle of Proxy, we need to check the code of $Proxy0.class. Since $Proxy0.class is in memory, we need to write it locally. Not much nonsense, the method is as follows:

In the main method of calling the dynamic proxy, add

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");    
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", true);//这个不对

In this way, com.sun.proxy.$ProxyX.class will be generated in the root directory of the project when running the code, and we can understand the process of Proxy through decompilation.

Of course, it is also possible to

Proxy.getProxyClass(真正用到的类.class.getClassLoader(), 真正用到的类.class)); 

to get the bytecode and write it locally.

Note: The above parameter is not a Boolean value, but a string "true". When you see System.getProperties, you will definitely think that this is a system property. Out of curiosity, let's see what system properties are:

public class Main {

    public static void main(String[] args) {
        Set set = System.getProperties().keySet();
        if (!set.isEmpty()) {
            Iterator iterator = set.iterator();
            Object key = null;
            while (iterator.hasNext()) {
                key = iterator.next();
                System.out.println(key + " : " + System.getProperties().get(key));
            }
        }
    }
}

The printed result is:

java.runtime.name : Java(TM) SE Runtime Environment
sun.boot.library.path : D:\Program Files\Java8\jdk1.8.0.181\jre\bin
java.vm.version : 25.181-b13
java.vm.vendor : Oracle Corporation
。。。

Because the result is too long, only a part is intercepted here. But you will find that there is no sun.misc.ProxyGenerator.saveGeneratedFiles in the system properties. So where does this attribute come from? If there is no source, this is a magic value. We will not know if the system changes in the future. Let’s find the source of this value from the Proxy code and why it is the string true instead of boolean true .

The following line of code must be used when using Proxy, which is also the only entry of Proxy, so sun.misc.ProxyGenerator.saveGeneratedFiles must also be related to this class.

Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
            .getClass().getInterfaces(), handler);

Follow up on newProxyInstance and find the return code:

insert image description here

It can be seen that the return value is instantiated through Constructor. If you have used reflection, you must be familiar with this class. Then the type of this instance is the type of c1, and c1 is obtained through getProxyClass0, continue to follow up:

insert image description here

Through the code, we can see that ProxyClassCache is of WeakCache type, so the return value of getProxyClass0 is in ProxyClassCache and obtained through key-value pairs, so let's take a look at how ProxyClassCache is implemented:

insert image description here

So the return value is of ProxyClassFactory type, continue to follow up:

insert image description here

As can be seen from the structure diagram of ProxyClassFactory, in this factory mode, all instances are returned through the apply method.

insert image description here

Through the comments and code, we can see that the proxy class is generated through ProxyGenerator.generateProxyClass, continue to follow up:

insert image description here

I did not configure the source code of the file here, it was decompiled through the class file, so there is no comment; but according to the variable name and the I/O exception thrown, it can be guessed that this is the logic that controls whether the proxy class file is generated or not, so let's see See how saveGeneratedFiles is defined:

private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));

You can see that this is the attribute we wrote at the beginning of the article, which proves that we have found the right one, and continue to follow up GetBooleanAction:

public class GetBooleanAction implements PrivilegedAction<Boolean> {
    private String theProp;

    public GetBooleanAction(String var1) {
        this.theProp = var1;
    }

    public Boolean run() {
        return Boolean.getBoolean(this.theProp);
    }
}

This class is very simple. It just implements the PrivilegedAction interface. PrivilegedAction has only one run method and a bunch of comments. We can make a bold guess: the purpose of implementing this interface is to provide the corresponding value with the run method, and continue to follow up Boolean.getBoolean:

public static boolean getBoolean(String name) {
    boolean result = false;
    try {
        result = parseBoolean(System.getProperty(name));
    } catch (IllegalArgumentException | NullPointerException e) {
    }
    return result;
}

Since the parameter of parseBoolean is of type String, this explains why it is not of type boolean at the beginning of the article.

Guess you like

Origin blog.csdn.net/niuzhucedenglu/article/details/82970897