1、基本概念
AOP静态代理:AOP的静态代理主要是在虚拟机启动时通过改变目标对象字节码的方式来完成对目标对象的增强,它比动态代理效率更高。
Java agent:java agent通常可理解为一个“插件”,本质是一个精心提供的jar文件,我们精心的编码在其中描写需要进行的操作,这些操作通过java.lang.Instrument包提供的API进行Java应用程序的Instrument,比如可以动态在方法执行前后新增执行时间的统计。
java.lang.instrument:JDK1.5之后提供的用于装备Java应用程序的工具API,允许JavaAgent程序Instrument(装备)在JVM上运行的应用程序,通常的做法是提供方法用于在字节码中插入要执行的附加代码。JDK1.6后提供两种实现:命令行(-javaagent)形式在应用程序启动前处理(premain方式);在应用程序启动后的某个时机处理(agentmain方式)。
ClassFileTransformer:JavaAgent的代码中需要提供一个它的实现类,以进行自定义的字节码转换。
Javaassist:它是一个处理Java字节码类库。能允许在Java程序运行时定义类,并能在JVM加载类时修改类文件。
流程图:
2、应用场景
Pinpoint分布式链路
SkyWalking分布式链路
3、实现步骤
- 定义一个 resources/META-INF/MANIFEST.MF 文件,在其中添加 premain-class 配置项。
- 创建 premain-class 配置项指定的类,并在其中实现 premain() 方法,方法签名如下:
public static void premain(String agentArgs, Instrumentation inst){
...
}
- 将 MANIFEST.MF 文件和 premain-class 指定的类一起打包成一个 jar 包。
- 使用 -javaagent 指定该 jar 包的路径即可执行其中的 premain() 方法。
4、小案例
1)创建一个代理的jar
github: https://github.com/fomeiherz/agent-example
jar打包:mvn clean package
打包完成后,会在 {base}/target 下生成一个agent.jar ,一会启动会用到。
2)创建测试类
本地任意目录创建文件:App.java
public class App {
public static void main(String[] args) {
new App().test();
}
private void test() {
System.out.println("hello agent.");
}
}
把第1步打包的agent.jar拷贝到App.java文件目录下,然后编译启动。
编译:javac App.java
启动:java -javaagent:agent.jar App