從JVM中dump出動態代理生成的class

因爲動態代理生成的class是直接以二進制的方式加載進內存中的,並無對應的.class文件生成,因此若是想經過反編譯工具查看動態代理生成的代碼須要經過特殊的手段來處理。java

方案一

設置運行環境變量,運行後會把class文件生成在classpath目錄下windows

//動態代理時生成class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");

缺點是隻適用於JDK動態代理jvm

方案二

使用ClassDump,能夠dump出JVM中全部已加載的class。ClassDump位於$JAVA_HOME/lib/sa-jdi.jar中(注:windows版本JDK從1.7開始纔有此工具),直接以命令行執行。ide

#查看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/727938this

相關文章
相關標籤/搜索