从JVM中dump出动态代理生成的class

数字溯光者
• 阅读 9160

由于动态代理生成的class是直接以二进制的方式加载进内存中的,并没有对应的.class文件生成,所以如果想通过反编译工具查看动态代理生成的代码需要通过特殊的手段来处理。

方案一

设置运行环境变量,运行后会把class文件生成在classpath目录下

//动态代理时生成class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

缺点是只适用于JDK动态代理

方案二

使用ClassDump,可以dump出JVM中所有已加载的class。ClassDump位于$JAVA_HOME/lib/sa-jdi.jar中(注:windows版本JDK从1.7开始才有此工具),直接以命令行执行。

#查看PID
E:\work\Test\bin>jps

#缺省输出该PID下所有已加载的class文件至./目录
E:\work\Test\bin>java -classpath ".;./bin;%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.tools.jcore.ClassDump <PID>
//导入sa-jdi.jar包,实现ClassFilter接口,只输出匹配的class文件
public class MyFilter implements ClassFilter{

    @Override
    public boolean canInclude(InstanceKlass arg0) {
        return arg0.getName().asString().startsWith("com/sun/proxy/$Proxy0");
    }
    
}
#查看PID
E:\work\Test\bin>jps

#使用ClassFilter输出匹配的class文件,并指定输出目录
E:\work\Test\bin>java -classpath ".;./bin;%JAVA_HOME%/lib/sa-jdi.jar" -Dsun.jvm.hotspot.tools.jcore.filter=proxy.MyFilter -Dsun.jvm.hotspot.tools.jcore.outputDir=e:/dump sun.jvm.hotspot.tools.jcore.ClassDump <PID>

此方案基于JVM层的ClassDump所以可以支持javassist、cglib、asm动态生成的class。

最后贴下JDK动态代理反编译出来的代码

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 proxy.Run;    //目标代理类接口

//继承了Proxy类,实现目标代理类接口
public final class $Proxy0
  extends Proxy
  implements Run
{
  private static Method m1;
  private static Method m3;
  private static Method m0;
  private static Method m2;
  
  public $Proxy0(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      //获取目标代理类的方法
      m3 = Class.forName("proxy.Run").getMethod("run", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
  
  //方法重写
  public final String run()
  {
    try
    {
      //this.h就是InvocationHandler的实现类了,调用invoke方法,在实现类里面做拦截处理
      return (String)this.h.invoke(this, m3, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
}

参考

http://rednaxelafx.iteye.com/blog/727938

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
CGLIB介绍与原理(通过继承的动态代理)
一、什么是CGLIB?CGLIB是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。通常可以使用Java的动态代理创建代理,但当要代理的类没有实现接口或者为了更好的性能,CGLIB是一个好的选择。二、CGLIB原理CGLIB原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的
Easter79 Easter79
3年前
Spring的两种代理JDK和CGLIB的区别浅谈
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Easter79 Easter79
3年前
Spring中的AOP(三)——基于Annotation的配置方式(一)
    AspectJ允许使用注解用于定义切面、切入点和增强处理,而Spring框架则可以识别并根据这些注解来生成AOP代理。Spring只是使用了和AspectJ5一样的注解,但并没有使用AspectJ的编译器或者织入器,底层依然使用SpringAOP来实现,依然是在运行时动态生成AOP代理,因此不需要增加额外的编译,也不需要AspectJ的织入器支持。
Stella981 Stella981
3年前
ClassLoader解惑
一、什么是Classloader    一个Java程序要想运行起来,首先需要经过编译生成.class文件,然后创建一个运行环境(jvm)来加载字节码文件到内存运行,而.class文件是怎样被加载中jvm中的就是JavaClassloader所做的事情。    那么.class文件什么时候会被类加载器加载到j
Easter79 Easter79
3年前
Spring的Aop调用当前类的两种方法
我们知道Spring对于AOP实现有两种方法,如果类是接口实现类,则采用JDK动态代理实现AOP。如果类没有实现接口,则采用cglib生成子类做增强,以实现代理类的目的,其实运行时找到的是这个代理类,而不是原类。所以在一个代理类中调用内部的方法,是不是再走AOP逻辑的,那有什么好的方法可以解决这种问题吗?基于上面的思路有两种解决办法方法一:直接从
Stella981 Stella981
3年前
SpringAOP动态代理技术自动生成代理类原理演示
//如下是自动生成代理类的逻辑演示:为了解耦合将类的方法单纯在代理类里调用;额外功能都在代理类里实现代理类的存在的问题就是开发代码量大代码冗余.为了解决这类问题使用AOP动态代理自动生成代理类publicinterfaceMan{publicvoidalive();//提供一个接口}public
Wesley13 Wesley13
3年前
CGLIB代理基础
  本文意在讲解CGLIB的基础使用及基本原理。一、CGLIB的基本原理:  依赖ASM字节码工具,通过动态生成实现接口或继承类的类字节码,实现动态代理。  针对接口,生成实现接口的类,即implements方式;针对类,生成继承父类的类,即extends方式。二、为什么使用CGLIB?  JDK的动态代理只能基于接口,有时候我们想基于类
Easter79 Easter79
3年前
Spring的两种动态代理:Jdk和Cglib 的区别和实现
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Stella981 Stella981
3年前
Android动态加载之ClassLoader详解
Dalvik虚拟机如同其他Java虚拟机一样,在运行程序时首先需要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载可以从class文件中读取,也可以是其他形式的二进制流。因此,我们常常利用这一点,在程序运行时手动加载Class,从而达到代码动态加载执行的目的。只不过Android平台上虚拟机运行的是Dex字节码,一种对class文件优化的产物
Wesley13 Wesley13
3年前
Java动态代理机制解析
动态代理是指在运行时动态生成代理类。不需要我们像静态代理那个去手动写一个个的代理类。生成动态代理类有很多方式:Java动态代理,CGLIB,Javassist,ASM库等。这里主要说一下Java动态代理的实现。Java动态代理InvocationHandler接口Java动态代理中,每一个
Wesley13 Wesley13
3年前
Java动态代理
jdk动态代理实现原理:利用字节码技术,生成新的class文件,来达到动态代理效果。新的class文件是怎么组织的?由于代理目标是接口,则通过实现接口和继续代理类来完成。看看下面的例子更容易明白。demo接口publicinterfacePeoPleInterface{
数字溯光者
数字溯光者
Lv1
城中桃李愁风雨,春在溪头荠菜花。
文章
4
粉丝
0
获赞
0