1:Java Agent简介
Java Agent 这个技术出现在 JDK1.5 之后,对于大多数人来说都比较陌生,但是多多少少又接触过,实际上,我们平时用的很多工具,都是基于 Java Agent 实现的,例如常见的热部署 JRebel,各种线上诊断工具如阿里开源的 Arthas,还有调用链追踪的SKywalking。
其实 Java Agent 一点都不神秘,也是一个 Jar 包,只是启动方式和普通 Jar 包有所不同,对于普通的Jar包,通过指定类的 main 函数进行启动,但是 Java Agent 并不能单独启动,必须依附在一个 Java 应用程序运行。
我们可以使用 Agent 技术构建一个独立于应用程序的代理程序,用来协助监测、运行甚至替换其他 JVM 上的程序代码,使用它可以实现虚拟机级别的 AOP 功能等等。
2:Java Agent开发
import java.lang.instrument.Instrumentation;/*** 接下来还需要创建 MANIFEST.MF 文件并打包,这里我们直接使用 maven-assembly-plugin 打包插件来完成这两项功能。<br/>* 在 pom.xml 中引入 maven-assembly-plugin 插件并添加相应的配置,请移步到pom.xml。<br/>* 打包命令:mvn package -Dcheckstyle.skip -DskipTests<br/>* 启动脚本添加:-javaagent:javaagent路径/demo-agent.jar<br/>** @author: Cookie.Joo* @create: 2020/11/24*/
public class TestAgent {/*** premain() 方法有两个重载,如下所示,如果两个重载同时存在,【1】将会被忽略,只执行【2】:* @param agentArgs -javaagent 命令携带的参数.* @param inst 操作类的重要接口.**//*** 【1】一个参数方法** @param agentArg*/public static void premain(String agentArg) {System.out.println("this is a java agent only one arg");System.out.println("参数:" + agentArg + "\n");}/*** 【2】两个参数方法** @param agentArg* @param inst*/public static void premain(String agentArg, Instrumentation inst) {System.out.println("agent premain two args");System.out.println("参数:" + agentArg + "\n");}
}
打包需要特殊处理,这里咱们用maven插件来完成,否则是要在META-INF 目录中的生成MANIFEST.MF文件编写一点代码,其实也就是描述你的premain在哪的问题,用插件自动解决该问题。
<build><finalName>demo-agent</finalName><plugins><!-- 请看这个plugin即可 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>2.4</version><configuration><appendAssemblyId>false</appendAssemblyId><!-- 将TestAgent的所有依赖包都打到jar包中--><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><!-- 添加MANIFEST.MF中的各项配置--><manifest><!-- 添加 mplementation-*和Specification-*配置项--><addDefaultImplementationEntries>true</addDefaultImplementationEntries><addDefaultSpecificationEntries>true</addDefaultSpecificationEntries></manifest><!-- 将 premain-class 配置项设置为com.xxx.TestAgent--><manifestEntries><Can-Retransform-Classes>true</Can-Retransform-Classes><Can-Redefina-Classes>true</Can-Redefina-Classes><Premain-Class>com.demo.agent.TestAgent</Premain-Class></manifestEntries></archive></configuration><executions><execution><!-- 绑定到package生命周期阶段上 --><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins>
</build>
最后打包成jar,META-INF 目录中生成MANIFEST.MF如下描述文件
Manifest-Version: 1.0
Implementation-Title: demo-agent
Implementation-Version: 0.0.1-SNAPSHOT
Archiver-Version: Plexus Archiver
Built-By: cookiejoo
Agent-Class: com.demo.agent.TestAgent
Specification-Title: demo-agent
Implementation-Vendor-Id: demo-agent
Can-Redefina-Classes: true
Premain-Class: com.demo.agent.TestAgent
Can-Retransform-Classes: true
Created-By: Apache Maven 3.6.1
Build-Jdk: 1.8.0_77
Specification-Version: 0.0.1-SNAPSHOT
3:Java Agent启动
随便找个main方法启动一下,启动应用必须加-javaagent参数,代码图中已经给出实例
最后看结果,premain方法两个参数的生效且在main方法之前就执行了
这就是Java Agent的一个入门程序,大概来认识一下,下次再来点高级的写法,比如通过Java Agent修改动态修改代码返回值,新增字段等骚操作。