java探针之修改类字节码文件

本文介绍了java探针如何利用javaAgent和ASM动态修改类文件,实现监控方法耗时和调用路径。通过Instrumentation接口,可以在JVM加载class时介入,使用ASM框架对字节码进行修改,实现类的动态增强。同时探讨了Instrumentation的实现原理,涉及到JVMTI和ClassFileTransformer接口,以及ASM、Javassist、Byte Buddy等字节码生成框架。
摘要由CSDN通过智能技术生成

java探针利用了javaAgent + ASM字节码注入工具实现了动态修改类文件的功能。像skywalking和arthas都使用到了这个技术。
具体原理为:

jdk1.5以后引入了javaAgent技术,javaAgent是运行方法之前的拦截器。我们利用javaAgent和ASM字节码技术,在JVM加载class二进制文件的时候,利用ASM动态的修改加载的class文件,在监控的方法前后添加计时器功能,用于计算监控方法耗时,同时将方法耗时及内部调用情况放入处理器,处理器利用栈先进后出的特点对方法调用先后顺序做处理,当一个请求处理结束后,将耗时方法轨迹和入参map输出到文件中,然后根据map中相应参数或耗时方法轨迹中的关键代码区分出我们要抓取的耗时业务。最后将相应耗时轨迹文件取下来,转化为xml格式并进行解析,通过浏览器将代码分层结构展示出来,方便耗时分析。

上篇我们介绍了JavaAgent的基本使用,下面介绍如何去动态的修改类的字节码文件,这个才是agent实现更强大功能的核心所在!

Instrumentation接口

Instrumentation接口位于jdk1.6包java.lang.instrument包下,Instrumentation指的是可以独立于应用程序之外的代理程序,可以用来监控和扩展JVM上运行的应用程序,相当于是JVM层面的AOP。

功能:
监控和扩展JVM上的运行程序,它可以替换和修改java类的字节码以便采集数据,用于监控,性能统计,覆盖率分析,事件记录等。可以用在程序启动时,也可以用于程序运行时动态attach。

比如说一个Java程序在JVM上运行,这时如果需要监控JVM的状态,除了使用JDK自带的jps等命令之外,就可以通过instrument来更直观的获取JVM的运行情况;
或者一个Java方法在JVM中执行,如果我想获取这个方法的执行时间又不想改代码,常用的做法是通过Spring的AOP来实现,而AOP通过面向切面编程,而instrument是在JVM层面上直接改动java方法来实现。

public interface Instrumentation{
   
    //添加ClassFileTransformer
    void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

    //添加ClassFileTransformer
    void addTransformer(ClassFileTransformer transformer);

    //移除ClassFileTransformer
    boolean removeTransformer(ClassFileTransformer transformer);

    //是否可以被重新定义
    boolean isRetransformClassesSupported();

    //重新定义Class文件
    void redefineClasses(ClassDefinition... definitions)
        throws ClassNotFoundException, UnmodifiableClassException;

    //是否可以修改Class文件
    boolean isModifiableClass(Class<?> theClass);

    //获取所有加载的Class
    @SuppressWarnings("rawtypes")
    Class[] getAllLoadedClasses();

    //获取指定类加载器已经初始化的类
    @SuppressWarnings("rawtypes")
    Class[] getInitiatedClasses(ClassLoader loader);

    //获取某个对象的大小
    long getObjectSize(Object objectToSize);

    //添加指定jar包到启动类加载器检索路径
    void appendToBootstrapClassLoaderSearch(JarFile jarfile);

    //添加指定jar包到系统类加载检索路径
    void appendToSystemClassLoaderSearch(JarFile jarfile);

    //本地方法是否支持前缀
    boolean isNativeMethodPrefixSupported();

    //设置本地方法前缀,一般用于按前缀做匹配操作
    void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix);
}

要是定义了操作java类的class文件方法,这里又涉及到了ClassFileTransformer接口,这个接口的作用是改变Class文件的字节码,返回新的字节码数组,源码如下:

public interface ClassFileTransformer{
   

    byte[] transform(ClassLoader loader, String className, Class<?
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值