文档章节

instrumentation 功能介绍(javaagent)

robin-yao
 robin-yao
发布于 2015/08/09 15:34
字数 1074
阅读 5229
收藏 7

    Instrumentation JDK中对它介绍如下:这个类为JVM上运行时的程序提供测量手段。很多工具通过Instrumenation 修改方法字节码 实现收集数据目的。这些通过Instrumentaion搜集数据的工具不会改变程序的状态和行为。这些良好的工具包括  monitoring agents  , ,profilers, coverage analyzers, 和 event loggers。

    有两种方式来获取Instrumentation接口实例:

  •      启动JVM时指定agent类。这种方式,Instrumentation的实例通过agent class的premain方法被传入。

  •      JVM提供一种当JVM启动完成后开启agent机制。这种情况下,Instrumention实例通过agent代码中的的agentmain传入。

    java agent 在JDK package specification中解释:一个agent 是被作为Jar 文件形式来部署的。在Jar文件中manifest中指定哪个类作为agent类。具体的实现包括

通过命令行直接指定选项开启agent,也支持JVM启动程序后,通过工具attach到该程序上。


    下面通过例子来说明javaagent + Instrumentation的用法。

    通过在程序启动前  preagent方式:(该例子实现输出所有JVM加载类名字,并在People类的 sayHello 方法调用前后加入log)

   1 people类

public class People {

    public void sayHello(){
        System.out.println("hello !!!!");
    }
}

    2 实现一个 ClassFileTransformer类:

        agent通过该具体实现来实现转换加载到JVM中class files。这种类的转换发生在类文件被载入JVM之前。因此这可以实现类AOP编程的效果。

public class PeopleClassFileTransformer implements ClassFileTransformer {

    /**
     * 通过javassist修改字节码
     * @param loader
     * @param className
     * @param classBeingRedefined
     * @param protectionDomain
     * @param classfileBuffer
     * @return
     * @throws IllegalClassFormatException
     */
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        System.out.println("load class:"+className);

        if("com.yao.intrumentation.People".equals(className)){
            try {
                //通过javassist修改sayHello方法字节码

                CtClass ctClass= ClassPool.getDefault().get(className.replace('/','.'));

                CtMethod sayHelloMethod=ctClass.getDeclaredMethod("sayHello");

                sayHelloMethod.insertBefore("System.out.println(\"before sayHello----\");");

                sayHelloMethod.insertAfter("System.out.println(\"after sayHello----\");");

                return ctClass.toBytecode();

            } catch (NotFoundException e) {
                e.printStackTrace();
            } catch (CannotCompileException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        return classfileBuffer;
    }
}

  3 编写agent,该类必须包含premain方法。并在META-INF 中添加MANIFEST.MF ,在清单中添加

Premain-Class: com.yao.intrumentation.MyAgent
public class MyAgent {

    /**
     * 该方法是一个类作为agent类必备的
     * @param agentArgs
     * @param inst
     */
    public static void premain(String agentArgs,Instrumentation inst){

        //加入ClassFileTransfomer
        inst.addTransformer(new PeopleClassFileTransformer());
    }

}

  4 打包agent类(这里可以把上面的 ClassFileTransfer MyAgent单独拿出来打包 。这里为了方面把所有的代码都放到一起了。。)

    代码编译后  在target/classes/下打包   加 m 参数是指定MANIFEST

jar -cvfm myagent.jar META-INF/MANIFEST.MF *         // 在自己项目目录下执行 比如maven目录结构 
                                                     // 在编译后的target/class/下执行

 5 测试main类:

public class TestMain {
    public static void main(String[]args){
        People people=new People();
        people.sayHello();
    }
}

  启动 这里为了方便解决引用的javassist jar包 classpath问题,我直接在Intellij 指定VM参数启动上面的main 方法,这样就不用在命令行里手工设定classpath。

-javaagent:/Users/yao/workspace/private/JavaSPI/target/classes/myagent.jar 指代我打包的agent jar 位置。

 

结果输入如下:

load class:java/lang/invoke/MethodHandleImpl
load class:java/lang/invoke/MethodHandleImpl$1
load class:java/lang/invoke/MethodHandleImpl$2
load class:java/util/function/Function
load class:java/lang/invoke/MethodHandleImpl$3
load class:java/lang/invoke/MethodHandleImpl$4
load class:java/lang/ClassValue
load class:java/lang/ClassValue$Entry
load class:java/lang/ClassValue$Identity
load class:java/lang/ClassValue$Version
load class:java/lang/invoke/MemberName$Factory
load class:java/lang/invoke/MethodHandleStatics
load class:java/lang/invoke/MethodHandleStatics$1
load class:sun/misc/PostVMInitHook
load class:sun/launcher/LauncherHelper
load class:com/yao/intrumentation/TestMain
load class:sun/launcher/LauncherHelper$FXHelper
load class:java/lang/Class$MethodArray
load class:java/lang/Void
load class:com/yao/intrumentation/People
before sayHello----
hello !!!!
after sayHello----
load class:java/lang/Shutdown
load class:java/lang/Shutdown$Lock

   下面简单介绍通过attach到正在运行的JVM程序的 agentmain方式

   1 编写agent类

public class MainAgent {
    public static void agentmain(String args, Instrumentation inst){
        Class[] classes = inst.getAllLoadedClasses();
        for(Class cls :classes){
            System.out.println(cls.getName());
        }

    }
}

  2 写一个长时间运行main

public class RunningApp {
    public static void main(String[]args) throws InterruptedException {
        People people=new People();
        Thread.sleep(1000*1000);
    }
}

  3 修改MANIFEST.MF

Agent-Class: com.yao.intrumentation.MainAgent

  用类似上面的方法打包成jar

  4 编写attach 程序

public class TestMainAgent {
    public static void main(String[]args) throws InterruptedException, IOException, AgentLoadException, AgentInitializationException, AttachNotSupportedException {
        VirtualMachine vm = VirtualMachine.attach(args[0]); //正在运行的java 程序 ps id
        vm.loadAgent("/Users/yao/workspace/private/JavaSPI/target/classes/agentmain.jar");
        //刚刚编译好的agent jar 位置
    }
}

运行 把 RunningApp启动后  jps 拿到ps id ,传给上面的程序,运行即可看到JVM加载的所有类文件

转载注明:http://my.oschina.net/robinyao/blog/489767

具体代码:https://github.com/WangErXiao/JavaSPI/tree/master/src/main/java/com/yao/intrumentation

© 著作权归作者所有

共有 人打赏支持
robin-yao
粉丝 161
博文 54
码字总数 61436
作品 0
杭州
私信 提问
java的premain

特性 在类的字节码载入JVM前会调用ClassFileTransformer的transform方法,从而实现修改原类方法的功能。 原理 JVMTI(Java Virtual Machine Tool Interface)是一套本地编程接口集合,它提供...

go4it
2016/10/15
5
0
Instrumentation 功能介绍(javaagent)

利用 Java 代码,即 java.lang.instrument 做动态 Instrumentation 是 Java SE 5 的新特性,它把 Java 的 instrument 功能从本地代码中解放出来,使之可以用 Java 代码的方式解决问题。使用 ...

beibugulf
2016/10/21
82
0
Java代理-Javassist

代理 (agent) 是在你的main方法前的一个拦截器 (interceptor),也就是在main方法执行之前,执行agent的代码。agent的代码与你的main方法在同一个JVM中运行,并被同一个system classloader装载...

ksfzhaohui
2014/09/02
0
0
Instrumentation介绍学习

Instrumentation介绍 Java Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修...

beibugulf
2016/10/21
6
0
Instrumentation 实践详解

利用 Java 代码,即 java.lang.instrument 做动态 Instrumentation 是 Java SE 5 的新特性,有了这样的功能,开发者就可以实现更为灵活的和 了,这样的特性实际上提供了,使得开发者无需对 ...

陶邦仁
2014/12/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

移植Modbus到STM32F103(2):移植FreeModbus到usart3并运行示例代码

FreeModbus是Modbus的一个被广泛移植的实现。其源码在github,最新版是1.6。 FreeModbus支持Modbus功能码里的0x01~0x06,0x0F~0x11和0x17,对一些功能比如异常诊断和读事件计数等功能码并没有...

Konstantine
今天
3
0
浅谈神经网络(神经网络篇)

背景 之前写过浅谈神经网络基础篇,简单介绍下机器学习这块内容,用于扫盲。本文正式将神经网络,这部分是深度学习的基础。了解完可以掌握强大的机器学习的方法,也可以更好的了解深度学习。...

Uknowzheng
今天
3
0
移动硬盘变为RAW格式后的修复

在Mac上使用自己的移动硬盘结果文件系统格式变为RAW; 在自己windows笔记本上使用chkdsk H: /F进行修复,修复日志如下: C:\Users\mengzhang6>chkdsk H: /F文件系统的类型是 NTFS。卷标是 do...

晨猫
今天
3
0
10 Git —— 标签管理

10 Git —— 标签管理 本节内容: 命令git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id;命令git tag -a <tagname> -m "blablabla..."可以指定标签信息;命令git......

lwenhao
今天
3
0
小程序设置垂直居中,水平居中

如果子容器中的view需要居中的话,那需要在父容器中设置居中 水平居中: display: flex; flex-direction: column; align-items: center; 垂直居中 display: flex;align-items: cen...

淘幻幻
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部