当前位置:   article > 正文

java agent了解与使用_java agent 获取运行时参数

java agent 获取运行时参数

目录

1. java.lang.instrument

2. 自定义agent

3. 使用举例

4. 系统图示


通过这篇文章,可以初步了解agent。包括instrument包、如何自定义agent、使用举例。

后续的例子为,向某个class method添加log,然后恢复原代码。agent执行后的结果为:

  1. // 如下为preAgent修改class字节码,main()内调用class某个方法的结果
  2. === before targetMethod method ===
  3. from main param
  4. // 如下为调用agent之后,调用class某个方法的结果
  5. === before targetMethod method ===
  6. person age is 10
  7. from main param101
  8. from main param101
  9. // 如下为调用agent恢复字节码的结果
  10. === before targetMethod method ===
  11. from main param

接下来一起了解下,想做到这个效果,需要掌握哪些知识。 

1. java.lang.instrument

1.1. what

提供了用于定义'给java应用安装测量仪器的工具'的API,工具例如监听或收集应用程序的信息,还可以修改代码逻辑,达到热部署的目的。允许定义的工具去修改class文件,即向方法的字节码中插入额外的字节码,以此实现仪器的行为。

1.2. 主要类

1.2.1 java.lang.instrument.ClassDefinition

定义了需要重定义的class和新的class bytes的绑定关系,其实例作为Instrumentation.redefineClasses方法的参数,

1.2.2. java.lang.instrument.ClassFileTransformer

agent需要实现该接口。在jvm定义class之前,转换class字节码。

1.2.3. java.lang.instrument.Instrumentation

提供了一些行为,用于向java代码添加仪器。这里所谓的仪器,就是方法中添加的额外字节码。用于为工具收集信息。不需要提供实现。

每次调用agent static方法,传递一个新的Instrumentation实例,可以随时调用它的行为。

addTransformer注册一个转换器,可通过参数设置该转换器是否支持二次转换,但前提是agent的配置也支持二次转换。
removeTransformer注销一个转换器
isRetransformClassesSupportedjvm配置是否支持class的二次转化。 要求agent JAR文件中Can-Retransform-Classes manifest attribute is set to true且jvm支持。
retransformClasses二次转化
isRedefineClassesSupportedjvm配置是否支持class的二次定义。 要求agent JAR文件中Can-Redefine-Classes manifest attribute is set to true且jvm支持。
redefineClasses二次定义,需要提供新的class字节码
isModifiableClassclass是否由 retransformation or redefinition修改过
getAllLoadedClassesjvm加载的所有class
getInitiatedClasses由参数classLoader参与初始化的class
appendToBootstrapClassLoaderSearch明确说明jar文件是由bootstrap classLoader定义的。
appendToSystemClassLoaderSearch明确说明jar文件是由system classLoader定义的。
isNativeMethodPrefixSupportedjvm配置是否支持setting a native method prefix。 要求agent JAR文件中Can-Set-Native-Method-Prefix manifest attribute is set to true且jvm支持。

2. 自定义agent

2.1. 自定义agent的入口

before jvm call main

  • 优先调用 public static void premain(String agentArgs, Instrumentation inst);找不到,则调用public static void premain(String agentArgs);

sometime after jvm call main

  • 优先调用 public static void agentmain(String agentArgs, Instrumentation inst);找不到,则调用public static void agentmain(String agentArgs)

需要考虑的问题:

  • 如何调用某个jvm中的afterAgent?
    • jdk ​​​tools.jar com.sun.tools.attach.VirtualMachine
  • 调用agent的参数规范
    • 指令种类
    • 关注的class
    • 关注的method
    • transformer的参数

2.2. 自定义transformer

需要考虑的问题:

  • 如何变更class字节码
    • javassist(门槛低,不需要了解class file规范。)
    • asm(门槛高,需要了解class file的规范,直接操控字节码。)
    • 看skywalking agent源码时发现的新工具bytebuddy
  • 使用javassist添加字节码需要注意什么?
    • insertAt lineNum是对于java文件而言
    • 不可以访问method定义的局部变量,否则编译失败;
    • 可以访问方法的入参
    • 可以访问实例的field
    • 可以自定义局部变量
  • 参数规范
  • 考虑针对哪些class和method
  • 如何恢复已转化的class

2.3. 定义manifest文件

  1. Manifest-Version: 1.0
  2. Main-Class: com.chl.demo.agent.AfterAgent
  3. Premain-Class: com.chl.demo.agent.PreAgent
  4. Agent-Class: com.chl.demo.agent.AfterAgent
  5. Can-Redefine-Classes: true
  6. Can-Retransform-Classes: true
  7. Can-Set-Native-Method-Prefix: false

2.4. jar包

需要考虑的问题:

  • 是否需要把依赖的包放入jar?
  • 如何包含manifest文件

2.5. 指令

preAgent和afterAgent均可用

  • java -javaagent:path/xxxagent.jar -jar xxxapplication.jar

仅afterAgent可用

  • java -jar xxxapplication.jar -javaagent:path/xxxagent.jar

3. 使用举例

https://github.com/chlInGithub/java_agent_demohttps://github.com/chlInGithub/java_agent_demo

本地演示步骤

run配置的application

效果为

  1. premain has two params s
  2. premain has two params e
  3. main
  4. === before targetMethod method ===
  5. from main param

jps找到上述应用的进程id

  1. // 例如
  2. jps
  3. 155696 ApplicationMain

修改字节码

AfterAgentClient main中设置上述查到的进程ID

修改agent jar包地址

run main

  1. // 控制台输出
  2. 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();
  3. person.setAge(10);
  4. if (null != person) {
  5. System.out.println("person age is " + person.getAge());
  6. }
  7. com/chl/demo/agent/target/AgentTarget
  8. classBeingRedefined is not null ? true
  9. classfileBuffer is not null ? true
  10. insertAt 0
  11. finally remove ok
  12. === before targetMethod method ===
  13. person age is 10
  14. from main param101
  15. from main param101

恢复修改

loadAgent第二个参数中1#改为2#

run main

  1. // 控制台输出
  2. agentmain has two params 2#com.chl.demo.agent.target.AgentTarget#targetMethod#1@System.out.println("=== this is from agentMain param1 ===");
  3. com/chl/demo/agent/target/AgentTarget
  4. RecoverTransformer classBeingRedefined is not null ? true
  5. RecoverTransformer classfileBuffer is not null ? true
  6. finally remove ok
  7. === before targetMethod method ===
  8. from main param

4. 系统图示

参考

Javassist Tutorial

java.lang.instrument (Java Platform SE 8 )

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/349146
推荐阅读
相关标签
  

闽ICP备14008679号