闲聊
最近在配置skywalking
的过程中发现了-javaagent:
这个配置,这里做一个简单的学习
什么是JavaAgent
网上似乎没有直接的文档介绍这个,只找了instrument包的相关文档,其内容页。其中的内容也都是介绍javaagent相关。
instrument包下核心就是字节码增强,此包下有2个核心接口ClassFileTransformer
,Instrumentation
-
ClassFileTransformer
:An agent provides an implementation of this interface in order to transform class files. -
ClassFileTransformer
:代理需要实现这个接口,并对class文件转化(增强) -
Instrumentation
:This class provides services needed to instrument Java programming language code. -
Instrumentation
:Instrumentation 为代码增强提供了必要的服务和功能。
有什么用及怎么用
有什么用
代码增强可以用于监控代理、分析器、覆盖分析器和事件记录器。
怎么用
上面介绍了这么多编码过程,如果想要能使用,则需要打成jar包,具体使用需要通过-javaagent
来让代码运行。总算知道为啥没有文档了,-javaagent
主要是用来让代理生效的,核心是instrument包
。
如果伴随jar包启动,需要创建premain方法,并在MANIFEST.MF
中指定Premain-Class: com.mountain.monk.MyAgent
如果是在启动后,再进行代理,则需要创建agentmain方法,并在MANIFEST.MF
中指定Agent-Class: com.mountain.monk.MyAgent
实现一个计算函数执行时间的功能
- 随便创建一个类,创建premain方法,此处我使用了
javassist
来生成字节码
public class MyAgent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new TimeTransformer(),true);
}
public static class TimeTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
// 这里我们限制下,只针对目标包下进行耗时统计
if (!className.startsWith("com/mountain/monk/")) {
return classfileBuffer;
}
CtClass cl = null;
try {
ClassPool classPool = ClassPool.getDefault();
cl = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
for (CtMethod method : cl.getDeclaredMethods()) {
method.addLocalVariable("start", CtClass.longType);
method.insertBefore("start = System.currentTimeMillis(); ");
method.insertAfter("System.out.println(\"「monk」methodName:" + method.getName() + ", cost: \" + (System" +
".currentTimeMillis() - start));");
}
return cl.toBytecode();
} catch (Exception e) {
System.err.println("Error transforming class: " + className);
e.printStackTrace();
}
return classfileBuffer;
}
}
}
- 创建
MANIFEST.MF
,注意最后要空一行
Premain-Class: com.mountain.monk.MyAgent
Can-Redefine-Calsses: true
Can-Retransform-Classes: true
- 配置maven,注意:我这里需要把依赖打包进去
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifestFile>src/main/resources/META-INF/MANIFEST.MF</manifestFile>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 配置Idea启动参数
-javaagent:/Users/chenhui/learn/monk_note/self_agent/target/self_agent-1.0-SNAPSHOT-jar-with-dependencies.jar
- 随便找一个代码启动
- 代码地址:https://github.com/Nortyr/monk_note/tree/main/self_agent
- 参考链接:https://docs.oracle.com/javase/6/docs/api/java/lang/instrument/package-summary.html