Java Agent探针技术详解示例

网友投稿 299 2022-07-23


目录什么是java agent?使用示例入门进阶(一款接口mock数据小插件)使用

什么是java agent?

在JVM中运行中,类是通过classLoader加载.class文件进行生成的。在类加载加载.class文件生成对应的类对象之前时,我们可以通过修改.class文件内容(就是字节码修改技术),达到修改类的目的。JDK提供了对字节码进行操作的一系列api,而使用这些api开发出的程序就可以称之为java agent。

java agent能做什么?

不修改目标应用达到代码增强的目的,就好像spring的aop一样,但是java agent是直接修改字节码,而不是通过创建代理类。例如skywalking就是使用java agent技术,为目标应用代码植入监控代码,监控代码进行数据统计上报的。这种方式实现了解耦,通用的功能。

文末附上了我写的一款接口mock agent。感兴趣的可以看看,学习一波。

使用示例

入门

创建maven工程

创建一个简单的maven工程:

添加agent类:

package com.hiwei;

import java.lang.instrument.Instrumentation;

public class DemoAgent {

/**

* 该方法在main方法之前运行

*/

public static void premain(String arg, Instrumentation instrumentation) {

System.out.println("执行premain方法");

}

}

pom.xml打包配置

添加打包插件:

maven-shade-plugin

package

shade

false

true

true

true

${premain.class}

${can.redefine.swVJRDGXclasses}

${can.retransform.classes}

将工程打成jar包,就可以使用了。打包很简单:

在target目录下就出现了jar包:

使用agent

创建测试类:

package com.hiwe.demo.cache;

public class TestCache {

public static void main(String[] args) {

System.out.println("测试类");

}

}

添加javaagent参数配置:

-javaagent:D:\person-project\demo-agent\target\demo-agent-1.0-SNAPSHOT.jar

运行测试类:

进阶(一款接口mock数据小插件)

流程

使用java agent为接口mock数据

agent类:

package com.hiwei.test.agent;

import com.hiwei.test.agent.utils.StringUtils;

import java.io.*;

import java.lang.instrument.Instrumentation;

import java.nio.charset.StandardCharsets;

public class DemoAgent {

/**

* 该方法在main方法之前运行

* @param arg 文件路径

* @param instrumentation

*/

public static void premain(String arg, Instrumentation instrumentation) {

//读取mock文件

try {

FileInputStream file = new FileInputStream(arg);

BufferedReader rd = new BufferedReader(new InputStreamReader(file, StandardCharsets.UTF_8));

String configStr = readToString(rd);

if(StringUtils.isNotEmpty(configStr)){

MockConfig.parseConfig(configStr);

instrumentation.addTransformer(new DemoTransformer());

}

} catch (Exception e) {

e.printStackTrace();

}

}

private static String readToString(Reader rd) throws IOException {

StringBuilder sb = new StringBuilder();

int i;

while ((i = rd.read()) != -1) {

sb.append((char) ihttp://);

}

return sb.toString();

}

}

mock数据配置类

package com.hiwei.test.agent;

import com.alibaba.fastjson.JSONObject;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

public class MockConfig {

private static Map> mockData = new HashMap<>();

public static void parseConfig(String configStr) {

JSONObject config = JSONObject.parseObject(configStr);

Set classNameSet = config.keySet();

classNameSet.forEach(className -> {

Map methodMock = new HashMap<>();

JSONObject methods = config.getJSONObject(className);

Set mSet = methods.keySet();

mSet.forEach(m -> {

methodMock.put(m, methods.get(m));

});

mockData.put(className, methodMock);

});

}

public static boolean isMock(String className) {

return !(mockData.get(className) == null);

}

public static Object getMockData(String className, String methodName) {

Map stringJSONObjectMap = mockData.get(className);

if (stringJSONObjectMap != null) {

return stringJSONObjectMap.get(methodName);

}

return null;

}

}

字节码操作类

package com.hiwei.test.agent;

import javassist.ClassPool;

import javassist.CtClass;

import javassist.CtMethod;

import java.lang.instrument.ClassFileTransformer;

import java.security.ProtectionDomain;

public class DemoTransformer implements ClassFileTransformer {

@Override

public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {

ClassPool classPool = ClassPool.getDefault();

String realClassName = className.replaceAll("/", ".");

//获取类

if(MockConfig.isMock(realClassName)){

try {

CtClass ctClass = classPool.get(realClassName);

CtMethod[] declaredMethods = ctClass.getDeclaredMethods();

for (CtMethod m : declaredMethods) {

String mName = m.getName();

Object mockData = MockConfig.getMockData(realClassName, mName);

if(mockData!=null){

String mock = String.format("if(true){%s}", mockData);

m.insertBefore(mock);

}

}

return ctClass.toBytecode();

} catch (Throwable e) {

e.printStackTrace();

}

}

return classfileBuffer;

}

}

配置文件:mock.json

{  "com.hiwei.test.DemoService":{  -- 类名    "add":"return 123;",   -- 方法名:mock代码    "delete&swVJRDGXquot;:"return \"mock delete\";",    "getUser": "com.hiwei.test.User user2 = new com.hiwei.test.User();return user2;"  }}

使用

配置参数:

-javaagent:D:\person-project\java-agent\demo-agent\target\demo-agent-1.0-SNAPSHOT.jar=D:\person-project\java-agent\agent-test\mock.json

源码链接:https://github.com/hiwei-zhang/java-agent


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:解决java连接虚拟机Hbase无反应的问题
下一篇:微信小程序获取手机号的完整实例(Java后台实现)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~