资讯专栏INFORMATION COLUMN

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

sherlock221 / 1624人阅读

摘要:方案一设置运行环境变量运行后会把文件生成在目录下动态代理时生成文件缺点是只适用于动态代理方案二使用可以出中所有已加载的。

由于动态代理生成的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:workTestin>jps

#缺省输出该PID下所有已加载的class文件至./目录
E:workTestin>java -classpath ".;./bin;%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.tools.jcore.ClassDump 
//导入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:workTestin>jps

#使用ClassFilter输出匹配的class文件,并指定输出目录
E:workTestin>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 

此方案基于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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67807.html

相关文章

  • 由「Metaspace容量不足触发CMS GC」而引发思考

    摘要:第一个大陡坡是应用发布,老年代内存占比下降,很正常。但此时老年代内存使用占比。因为后期并不会引发。可以看出,由于到达时候,触发了一次和一次。但触发时,占比并没用明显的规律。得出,扩容导致这个说法,其实是不准确的。 转载请注明原文链接:https://www.jianshu.com/p/468... 某天早上,毛老师在群里问「cat 上怎么看 gc」。 showImg(https://...

    StonePanda 评论0 收藏0
  • jvm调优-命令篇

    摘要:打印等待回收对象的信息可以看到当前队列中并没有等待线程执行方法的对象。一般情况,会到客户端用工具来分析用于生成虚拟机当前时刻的线程快照。 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole、大名鼎鼎的VisualVM,IBM的Memory Analyzer等等,但是在生产环境出现问题的时候,一方面工具的使...

    Lsnsh 评论0 收藏0
  • Javag工程师成神之路(2019正式版)

    摘要:结构型模式适配器模式桥接模式装饰模式组合模式外观模式享元模式代理模式。行为型模式模版方法模式命令模式迭代器模式观察者模式中介者模式备忘录模式解释器模式模式状态模式策略模式职责链模式责任链模式访问者模式。 主要版本 更新时间 备注 v1.0 2015-08-01 首次发布 v1.1 2018-03-12 增加新技术知识、完善知识体系 v2.0 2019-02-19 结构...

    Olivia 评论0 收藏0
  • 《深入理解Java虚拟机》(四)虚拟机性能监控与故障处理工具

    摘要:虚拟机性能监控与故障处理工具详解概述本文参考的是周志明的深入理解虚拟机第四章,为了整理思路,简单记录一下,方便后期查阅。虚拟机堆转储快照分析工具功能用于分析生成的。 虚拟机性能监控与故障处理工具 详解 4.1 概述 本文参考的是周志明的 《深入理解Java虚拟机》 第四章 ,为了整理思路,简单记录一下,方便后期查阅。 JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的Vis...

    gself 评论0 收藏0
  • Java开发 大厂面试整理

    摘要:用户态不能干扰内核态所以指令就有两种特权指令和非特权指令不同的状态对应不同的指令。非特权指令所有程序均可直接使用。用户态常态目态执行非特权指令。 这是我今年从三月份开始,主要的大厂面试经过,有些企业面试的还没来得及整理,可能有些没有带答案就发出来了,还请各位先思考如果是你怎么回答面试官?这篇文章会持续更新,请各位持续关注,希望对你有所帮助! 面试清单 平安产险 飞猪 上汽大通 浩鲸科...

    Scorpion 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<