在上一篇中我们已经介绍了java agent的相关概念和思想,给出了premain方式的实现代码。本篇主要是实现了attach方式,不同之处主要如下:
premain是静态修改,在类加载之前修改; attach是动态修改,在类加载后修改
要使premain生效重启应用,而attach不重启应用即可修改字节码并让其重新加载
可以看到attach的方式更加强大,其核心原理首先是找到相关的进程id, 然后根据进程id去动态修改相关字节码,具体的修改方式和premain无差,下面就直接给出详细实现。
项目结构(此处为了方便把主程序和Agent程序放在一起, 实际生产中肯定是分开的):
agentdemo
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── hebh
│ └── demo
│ ├── agent
│ │ ├── MyInstrumentationAgent.java
│ │ └── MyTransformer.java
│ └── application
│ ├── AgentLoader.java
│ ├── Launcher.java
│ ├── MyApplication.java
│ └── Runner.java
└── resources
├── META-INF
│ └── MANIFEST.MF
└── log4j2.xml
先看测试结果:
打成jar包
mvn clean package
运行主程序
java -jar target/myAgent-jar-with-dependencies.jar
运行agent程序, 注意带上系统的lib目录
java -Djava.ext.dirs=${JAVA_HOME}/lib -jar target/myAgent-jar-with-dependencies.jar LoadAgent
如下图所示,可以看到首先找到主程序的进程id为4477,然后再attach上去
image-20190126202600306
然后此时再看主程序的运行日志, 可以看到在attach后动态增加的字节码生效了,实现了方法耗时监控:
image-20190126203002824
详细代码:
MANIFEST.MF
Main-Class: com.hebh.demo.application.Launcher
Agent-Class: com.hebh.demo.agent.MyInstrumentationAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
pom
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/m