java动态代理生成$Proxy0源代码的操作

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java动态代理生成$Proxy0源代码的操作相关的知识,希望对你有一定的参考价值。

  1. $Proxy该类是动态生成的,在运行的时候生成。具体源代码的提取参考的是:http://www.cnblogs.com/ctgulong/p/5011614.html?utm_source=tuicool&utm_medium=referral的blog


2.根据上面博客的内容详细写一下生成源代码的过程。参考之前的项目http://yinyueml.blog.51cto.com/4841237/1876473

1)首先需要一个agent的生成类。javaagent主要功能如下:

  • 可以在加载class文件之前做拦截,对字节码做修改

  • 可以在运行期对已加载类的字节码做变更,但是这种情况下会有很多的限制,后面会详细说

  • 还有其他一些小众的功能

    • 获取所有已经加载过的类,这个功能让我们可以获取到动态代理的生成类的class文件,经过反编译后就可以查看源代码。

    • 获取所有已经初始化过的类(执行过clinit方法,是上面的一个子集)

    • 获取某个对象的大小

    • 将某个jar加入到bootstrap classpath里作为高优先级被bootstrapClassloader加载

    • 将某个jar加入到classpath里供AppClassloard去加载

    • 设置某些native方法的前缀,主要在查找native方法的时候做规则匹配

2)代码如下

package jdkReview;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

public class CustomAgent implements ClassFileTransformer {
 //
    public static void premain(String agentArgs, Instrumentation inst) {
        inst.addTransformer(new CustomAgent());
    }

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        if (!className.startsWith("java") && !className.startsWith("sun")) {
            // 既不是java也不是sun开头的
            // 导出代码
            int lastIndexOf = className.lastIndexOf("/") + 1;
            String fileName = className.substring(lastIndexOf) + ".class";
            exportClazzToFile("D:/javacode/", fileName, classfileBuffer);
            System.out.println(className + " --> EXPORTED Succeess!");
        }    
        return classfileBuffer;
    }

    /**
     * 
     * @param dirPath
     *目录以/结尾,且必须存在
     * @param fileName
     * @param data
     */
    private void exportClazzToFile(String dirPath, String fileName, byte[] data) {
        try {
            File file = new File(dirPath + fileName);
            if (!file.exists()) {
                file.createNewFile();    
            }    
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data);
            fos.close();    
        } catch (Exception e) {
            System.out.println("exception occured while doing some file operation");
            e.printStackTrace();
        }
    }
}

3)将CustomAgent导出为jar包,并且修改MANIFEST.MF文件内容如下:

Manifest-Version: 1.0
Premain-Class: jdkReview.CustomAgent

该配置主要是为了Premain-Class的作用就是表示带有premain静态方法的Class。

4)在运行使用java动态代理的Client类的时候加上jvm的参数

-javaagent:d:/customAgent.jar

然后运行后如下结果为:

proxyPattern/Client --> EXPORTED Succeess!
proxyPattern/GamePlayer --> EXPORTED Succeess!
proxyPattern/IGamePlayer --> EXPORTED Succeess!
proxyPattern/GamePlayIH --> EXPORTED Succeess!
com/sun/proxy/$Proxy0 --> EXPORTED Succeess!
有人再用我的账号登陆
登陆用户名:yinyueml;玩家:张三上线
张三正在打怪。
张三升级了

现在通过

exportClazzToFile("D:/javacode/", fileName, classfileBuffer);

中的配置路劲就可以找到$Proxy0.class的文件。

5)通过jad.exe反编译应用对$Proxy0.class进行反编译就可以获取到源代码。

以上是关于java动态代理生成$Proxy0源代码的操作的主要内容,如果未能解决你的问题,请参考以下文章

动态代理

Spring5动态代理报错com.sun.proxy.$Proxy0 cannot be cast to com.gzh.demo02.UserService

SpringAOP-JDK 动态代理和 CGLIB 代理

动态代理Java实现

java中静态代理和动态代理

动态代理模式