instrumentation 功能介绍(javaagent)

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

时间: 2024-10-24 19:26:06

instrumentation 功能介绍(javaagent)的相关文章

Spring学习之Jar包功能介绍(转)

spring.jar 是包含有完整发布模块的单个jar 包.但是不包括mock.jar, aspects.jar, spring-portlet.jar, and spring-hibernate2.jar. spring-src.zip就是所有的源代码压缩包. 除了spring.jar 文件,Spring 还包括有其它21 个独立的jar 包,各自包含着对应的Spring组件,用户可以根据自己的需要来选择组合自己的jar 包,而不必引入整个spring.jar 的所有类文件. spring-c

Exchange2016正式版功能介绍及全新安装配置

Exchange2016功能介绍及全新安装配置 说到Exchange服务相信很多人都在关注,微软在2015年更新了很多服务,从功能上来说确实做了很多优化及提升,具体就不多说了,微软在2015年10月1日发布了Exchange2016正式版,版本还是分为标准版和企业版,此次发布为多语言版本 同样微软在2015年发布了那些新产品呢 : 我们还是说说Exchange2016,从安装及官网文档上看微软从Exchange2010到Exchange2016角色上缩减了很多,从Exchange2010的Mai

Python中生成器和迭代器的功能介绍

生成器和迭代器的功能介绍 1. 生成器(generator) 1. 赋值生成器 1. 创建 方法:x = (variable for variable in iterable) 例如:x = (i for i in range(10)) print(x) >>> <generator object <genexpr> at 0x00000000006B85C8> 返回值:generator #使用元祖推导式的时候回变成一个生成器. 2. 调用 方法:x.__nex

友盟新功能介绍:在线参数-备用

作为开发者您是否也碰到过这些挠头问题: 刚上线不久的应用就要修改说明文字?应用添加广告后,如何平衡用户流失和广告收入情况?如何对游戏中的道具进行合理定价? 为帮助开发者告别频繁地更新应用版本,更好的比较版本之间的用户行为及习惯,友盟针对Android开发者新推出在线参数功能.通过在线参数功能,开发者可以远程动态修改应用中的参数值,灵活调整运营策略.iOS版本近期推出. 获得更多信息和体验在线参数功能请访问www.umeng.com 什么是在线参数 在线参数是友盟推出的新功能,可以让您动态修改应用

Python中set的功能介绍

Set的功能介绍 1.集合的两种函数(方法) 1. 集合的内置函数 交集 格式:x.__and__(y)等同于x&y 例如:s1 = {'a',1,} s2 = {'b',1,} s3 = {'b','d'} print(s1.__and__(s2)) >>> {1} print(s1.__and__(s3)) >>> set() 返回值:set #y只能是集合,当两个集合没有交集时,返回值为空集合. 判断是否是包含关系 格式:x.__contains__(y)

EXCEL基础内容学习笔记(二)Excel文档的基本组成与功能介绍

一.基本组成 (一)工作簿.工作表与单元格 (1)工作簿:一个Excel文档即为一个工作簿. (2)工作表:工作簿中的每个表. (3)单元格:打开Excel文档,在工作表中单击,出现的加粗四边形即为单元格.单元格由行和列组成,命名时由行和列说明,称为单元格名称或地址. 一个工作簿中有若干个工作表,每个工作表有许多单元格组成. 二.功能介绍 (1)标题栏:Excel文档最上端. (2)选项卡 (3)工作区:每一个打开的选项卡都含有若干工作区. (4)名称框:所选择的单元格的名字. (5)编辑栏:可

keepalived高可用的常用功能介绍

Keepalived的作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除,当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的web服务器.本篇文章会介绍keepalived的安装,配置,还有keepalived的一些脚本,keepalived+nginx高可用实现和keepalived双机互为主从的实现. keep

vsphere(vCenter功能介绍)四

今天我们来讲vcenter的功能 让大家熟悉熟悉 这就是 一个容器罢了 大家根据公司的环境 自由搭建 这个会经常操作 做HA时会用运到以下配置 然后我们把esxi41-2 的配合改了 比如说改改网络 配置啥的 然后在附加上去 前提要进入维护模式  导入后在退出维护模式就行了 ok 今天就讲到这里 大家一定要多点 并不是我写的这些功能就是全部的  拜 vsphere(vCenter功能介绍)四,布布扣,bubuko.com

带你走近AngularJS - 基本功能介绍

AngularJS是Google推出的一款Web应用开发框架.它提供了一系列兼容性良好并且可扩展的服务,包括数据绑定.DOM操作.MVC设计模式和模块加载等.本文专注于AngularJS 指令的使用,在我们进入主题之前,我们将快速浏览AngularJS的基本用法. AngularJS 不仅仅是一个类库,而是提供了一个完整的框架.它避免了您和多个类库交互,需要熟悉多套接口的繁琐工作.它由Google Chrome的开发人员设计,引领着下一代Web应用开发.也许我们5年或10年后不会使用Angula