赞
踩
目录
通过这篇文章,可以初步了解agent。包括instrument包、如何自定义agent、使用举例。
后续的例子为,向某个class method添加log,然后恢复原代码。agent执行后的结果为:
- // 如下为preAgent修改class字节码,main()内调用class某个方法的结果
- === before targetMethod method ===
- from main param
-
-
- // 如下为调用agent之后,调用class某个方法的结果
- === before targetMethod method ===
- person age is 10
- from main param101
- from main param101
-
- // 如下为调用agent恢复字节码的结果
- === before targetMethod method ===
- from main param
接下来一起了解下,想做到这个效果,需要掌握哪些知识。
提供了用于定义'给java应用安装测量仪器的工具'的API,工具例如监听或收集应用程序的信息,还可以修改代码逻辑,达到热部署的目的。允许定义的工具去修改class文件,即向方法的字节码中插入额外的字节码,以此实现仪器的行为。
定义了需要重定义的class和新的class bytes的绑定关系,其实例作为Instrumentation.redefineClasses方法的参数,
agent需要实现该接口。在jvm定义class之前,转换class字节码。
提供了一些行为,用于向java代码添加仪器。这里所谓的仪器,就是方法中添加的额外字节码。用于为工具收集信息。不需要提供实现。
每次调用agent static方法,传递一个新的Instrumentation实例,可以随时调用它的行为。
addTransformer | 注册一个转换器,可通过参数设置该转换器是否支持二次转换,但前提是agent的配置也支持二次转换。 |
removeTransformer | 注销一个转换器 |
isRetransformClassesSupported | jvm配置是否支持class的二次转化。 要求agent JAR文件中Can-Retransform-Classes manifest attribute is set to true且jvm支持。 |
retransformClasses | 二次转化 |
isRedefineClassesSupported | jvm配置是否支持class的二次定义。 要求agent JAR文件中Can-Redefine-Classes manifest attribute is set to true且jvm支持。 |
redefineClasses | 二次定义,需要提供新的class字节码 |
isModifiableClass | class是否由 retransformation or redefinition修改过 |
getAllLoadedClasses | jvm加载的所有class |
getInitiatedClasses | 由参数classLoader参与初始化的class |
appendToBootstrapClassLoaderSearch | 明确说明jar文件是由bootstrap classLoader定义的。 |
appendToSystemClassLoaderSearch | 明确说明jar文件是由system classLoader定义的。 |
isNativeMethodPrefixSupported | jvm配置是否支持setting a native method prefix。 要求agent JAR文件中Can-Set-Native-Method-Prefix manifest attribute is set to true且jvm支持。 |
before jvm call main
sometime after jvm call main
需要考虑的问题:
jdk tools.jar com.sun.tools.attach.VirtualMachine
需要考虑的问题:
- Manifest-Version: 1.0
- Main-Class: com.chl.demo.agent.AfterAgent
- Premain-Class: com.chl.demo.agent.PreAgent
- Agent-Class: com.chl.demo.agent.AfterAgent
- Can-Redefine-Classes: true
- Can-Retransform-Classes: true
- Can-Set-Native-Method-Prefix: false
需要考虑的问题:
preAgent和afterAgent均可用
仅afterAgent可用
https://github.com/chlInGithub/java_agent_demohttps://github.com/chlInGithub/java_agent_demo
本地演示步骤
run配置的application
效果为
- premain has two params s
- premain has two params e
- main
- === before targetMethod method ===
- from main param
jps找到上述应用的进程id
- // 例如
- jps
- 155696 ApplicationMain
修改字节码
AfterAgentClient main中设置上述查到的进程ID
修改agent jar包地址
run main
- // 控制台输出
- agentmain has two params 1#com.chl.demo.agent.target.AgentTarget#targetMethod#0@num = 2;int j = 101;param = param + 101;person = new com.chl.demo.agent.target.Person();
- person.setAge(10);
- if (null != person) {
- System.out.println("person age is " + person.getAge());
- }
- com/chl/demo/agent/target/AgentTarget
- classBeingRedefined is not null ? true
- classfileBuffer is not null ? true
- insertAt 0
- finally remove ok
- === before targetMethod method ===
- person age is 10
- from main param101
- from main param101
恢复修改
loadAgent第二个参数中1#改为2#
run main
- // 控制台输出
- agentmain has two params 2#com.chl.demo.agent.target.AgentTarget#targetMethod#1@System.out.println("=== this is from agentMain param1 ===");
- com/chl/demo/agent/target/AgentTarget
- RecoverTransformer classBeingRedefined is not null ? true
- RecoverTransformer classfileBuffer is not null ? true
- finally remove ok
- === before targetMethod method ===
- from main param
参考
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。