zoukankan      html  css  js  c++  java
  • Java探针技术-Instrumentation与ClassFileTransformer--字节码转换工具

      一个代理实现ClassFileTransformer接口用于改变运行时的字节码(class File),这个改变发生在jvm加载这个类之前。对所有的类加载器有效。

      class File这个术语定义于虚拟机规范3.1,指的是字节码的byte数组,而不是文件系统中的class文件。

    接口中只有一个方法:

    byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined,ProtectionDomain protectionDomain,byte[] 
    classfileBuffer)throws IllegalClassFormatException;


    ClassFileTransformer需要添加到Instrumentation实例中才能生效。

      获取Instrumentation实例的方法有2种:

      虚拟机启动时,通过agent class的premain方法获得
      虚拟机启动后,通过agent class的agentmain方法获得

      一旦agent参数获取到一个instrumentation,agent将会在任意时候调用实例中的方法。

      agent应该以jar包的形式存在,也就是说agent所在的类需要单独打包一个jar包,jar包的manifest文件指定agent class。文件中包含Premain-Class属性,agent class类必须实现public static premain 方法,实际应用的main方法在这个方法之后执行。

      premain 方法有2种签名,虚拟机优先调用

    public static void premain(String agentArgs, Instrumentation inst);

    如果没有上一种,则调用下一种

    public static void premain(String agentArgs); 

      通过这个 -javaagent:jarpath[=options] 参数,启动实际应用,就会自带agent。如果agent启动失败,jvm会终止。

      在虚拟机启动后,启动agent需要满足以下条件

      agent所在 的jar包的manifest文件中必须包含Agent-Class属性,值为agent class。

      agent类必须有public static agentmain方法。

      系统类加载器必须支持添加一个agent的jar包到系统类路径system class path

      这个方法也有2种签名,优先加载第一种,第一种没有,就加载第二种。

    public static void agentmain(String agentArgs, Instrumentation inst);
    
    public static void agentmain(String agentArgs);


      如果agent是在jvm启动后启动,那么premain就不会执行了。也就是说一个agent的2种方法只会启动一种。premain和agentmain是二选一的。agentmain抛出异常,不会导致jvm终止。

      第二种启动方式,先用jps获取进程id,然后启动agentjar包。

    VirtualMachine 在jdk的lib下面的tools.jar中,如果不在classpath的话,要加进去。

    VirtualMachine vm = VirtualMachine.attach("3134");
    try { 
      vm.loadAgent("/../agent.jar"); 
     } finally { 
      vm.detach(); 
    }

    agent的jar包中manifest中可以有的属性:

    Premain-Class 指定代理类
    Agent-Class 指定代理类
    Boot-Class-Path 指定bootstrap类加载器的搜索路径,在平台指定的查找路径失败的时候生效, 可选
    Can-Redefine-Classes 是否需要重新定义所有类,默认为false,可选。
    Can-Retransform-Classes 是否需要retransform,默认为false,可选。

      有两种ClassFileTransformer,根据canRetransform决定是哪一种。
      在向Instrumentation#addTransformer添加转换器的时候,会指定canRetransform,默认为false。决定retransformation是否可用。

      一旦一个transformer被注册到instrumentation中,每当一个类被定义(ClassLoader.defineClass)或被重新定义(Instrumentation.redefineClasses)时,它都会被调用。

      如果retransformation可用,那么一个类被retransformation(Instrumentation.retransformClasses)时,transformer也会被调用。

      存在多个transformers时,每个transformer会进行链式调用。

    多个transformers调用顺序:

    • Retransformation不可用的
    • Retransformation不可用的native 的transformation
    • Retransformation可用的
    • Retransformation可用的native 的transformation
    • 发生retransformations的时候,Retransformation不可用的transformers不会被调用。
    • 同一种transformers按照注册顺序执行。
    • native的transformers通过ClassFileLoadHook提供。
    •   如果一个transformer不想改变任何代码,那么返回null。否则,应该创建一个新的byte[],不能修改classfileBuffer。一个transformer抛出异常,后续的transformer依然会执行,抛异常和返回Null效果相同。

     

  • 相关阅读:
    经典8锁问题--助你彻底搞懂锁的概念
    linux上安装mysql
    Jenkins安装详解
    第一篇:实时网络日志分析器和交互式查看器--GoAccess安装
    Centos7上安装python3.7
    Nginx报错收集
    免费yum源镜像地址
    nginx日志文件切割
    腾讯云绑定和配置弹性网卡和添加弹性网卡
    LNMP-WEB应用环境搭建
  • 原文地址:https://www.cnblogs.com/liboware/p/12497621.html
Copyright © 2011-2022 走看看