Java Agent是什么?
Java Agent技术,也被称为Java代理、Java探针,从JDK1.5它就出现了,它允许程序员利⽤其构建⼀个独⽴于应⽤程序的代理程序。Java Agent本身就是个jar包,它利用JVM提供的Instrumentation API来更改加载在JVM中的现有字节码,Java Agent可以理解为是JVM级别的AOP。
Java Agent 怎么用?
Java Agent使用包括两个部分:代码实现和配置文件。
- 代码实现:这部分包括3个步骤:
- 实现ClassFileTransformer接口并重写transform方法。 ClassFileTransformer用于在JVM加载实现类之前转换类文件。
- 编写agent类 agent类中有两个方法:
premain
方法和agentmain
方法。premain
用于在代理方法执行前调用,在 JVM 启动时必须为其指明Java代理。它有两个实现agentmain
用于在代理方法运行时执行。
- 修改配置文件并打包
- 配置文件:配置文件名为MANIFEST.MF,需放在META-INF文件夹下或者在maven中配置。
Premain-Class:表示实现premain方法的类。
Agent-Class:表示实现agentmain方法的类。
Can-Redefine-Classes:表示Java agent是否可以重新定义被代理类。
Can-Retransform-Classes:表示是否允许Java Agent转换被代理类。
Java Agent的加载
Java Agent的加载分为静态加载和动态加载。
静态加载
在应用程序启动时加载Java代理称为静态加载,静态加载在任何代码执行之前在启动时修改字节码。它是以premain
方法为入口的,premain
方法有两个重载方法:
public static void premain(String agentArgs, Instrumentation inst)
public static void premain(String agentArgs)
- agentArgs:字符串参数,通过
-javaagent
传递 - inst:
java.lang.instrument.Instrumentation
类对象
JVM 会优先加载带 Instrumentation
对象参数的方法,加载成功忽略第二种;如果第一种没有,则加载第二种方法。
下面写个简单的例子玩一下静态加载:
- 新建一个maven项目并引入javassist包
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.2-GA</version>
</dependency>
- 新建一个
ClassFileTransformer
接口实现类PrintMethodCostTransformer,用户打印方法耗时
public class PrintMethodCostTransformer implements ClassFileTransformer {
private final String targetClassName;
public PrintMethodCostTransformer(String targetClassName) {
this.targetClassName = targetClassName;
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
try {
if (className != null) {
className = className.repla