javaagent又称java探针,结合javassist或asm等框架对字节码文件进行操作,从而更优雅的实现“AOP”等功能,减少对原代码的侵入性等。从而我们可以借此来实现微服务等的全链路追踪以及项目环境隔离等功能。好了话不多说,直接写示例吧:
示例分为两个项目:1、agent项目:agentdemo,2、被代理项目agentclient
我们要做的是:用agent项目来修改被代理项目中指定的hello方法,在原有的基础上添加一行代码输出一句话,又比如说我们要拦截redis发送命令的方法,从而获取相关的信息等。
一、先来写agent项目:
1、新建一个简单的maven项目
2、编辑pom文件,引入javassist依赖,以及指定premainClass(在main方法执行前会被执行的方法)生成MANIFEST.MF文件
4.0.0
com.zxing
agentdemo
1.0-SNAPSHOT
javassist
javassist
3.11.0.GA
org.apache.maven.plugins
maven-compiler-plugin
1.8
1.8
utf-8
org.apache.maven.plugins
maven-shade-plugin
3.0.0
package
shade
com.zxing.agent.App
3、创建FirstAgent类,实现ClassFileTransformer 接口,修改字节码
package com.zxing.agent;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
/**
* Created by ZXing at 2018/12/19
* QQ:1490570560
*/
public class FirstAgent implements ClassFileTransformer {
public final String injectedClassName = "com.zxing.agentclient.App";
public final String methodName = "hello";
public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
className = className.replace("/", ".");
// System.out.println(className);
if (className.equals(injectedClassName)) {
CtClass ctclass = null;
try {
ctclass = ClassPool.getDefault().get(className);// 使用全称,用于取得字节码类<使用javassist>
CtMethod ctmethod = ctclass.getDeclaredMethod(methodName);// 得到这方法实例
ctmethod.insertBefore("System.out.println(11111111);");//插入一行代码
return ctclass.toBytecode();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
return null;
}
}
4、创建App类,重写javaagent的premain方法
package com.zxing.agent;
import java.lang.instrument.Instrumentation;
/**
* Created by ZXing at 2018/12/19
* QQ:1490570560
*/
public class App {
public static void premain(String agentOps, Instrumentation inst) {
System.out.println("=========premain方法执行========");
System.out.println(agentOps);//-javaagent:xxxagent.jar=后携带的参数
// 添加Transformer
inst.addTransformer(new FirstAgent());
}
}
二、接下来我们写被代理项目,再新建一个项目agentclient
1、修改pom文件,指定main类,生成MANIFEST.MF文件(打开jar包可查看)
4.0.0
com.zxing
agentclient
1.0-SNAPSHOT
org.apache.maven.plugins
maven-shade-plugin
3.0.0
package
shade
com.zxing.agentclient.App
这个项目很简单,只有一个App类,main方法,以及我们要拦截的hello方法:
创建App类:
package com.zxing.agentclient;
/**
* Created by ZXing at 2018/12/19
* QQ:1490570560
*/
public class App {
public static void main(String[] args) {
hello();
}
public static void hello() {
System.out.println("this is agent-client output");
}
}
三、两个项目分别使用maven打包
打包:mvn clean package
将打包后的两个jar包以及javassist jar包拷贝至同一个文件夹下
四、命令启动被代理项目
java -javaagent:agentdemo-1.0-SNAPSHOT.jar=abc -jar agentclient-1.0-SNAPSHOT.jar
输出:
=========premain方法执行========
abc
11111111
this is agent-client output
这样这个简单的功能就实现了,,,,,,当然远不止以此,赶紧动手试试吧~~