JavaAgent概念:
Java Agent本质上可以理解为一个插件,该插件就是一个特制的Jar包。这个Jar包通过JVMTI(JVM Tool Interface)完成加载,最终借助JPLISAgent(Java Programming Language Instrumentation Services Agent)完成对目标代码的修改
实现一个JavaAgent:
JavaAgent有两种加载模式:静态加载,动态加载;静态加载是在jvm启动的同时加载Agent,动态加载是在目标jvm运行时加载Agent,两者的区别如下:
Skywalking只支持静态加载Agent的方式,也就是在JVM启动的时候,通过JVM参数加载进去,创建一个JaveAgent需要包含以下几步:
1、创建一个包含premain()方法的类
2、创建一个实现ClassFileTransform接口的Transfromer类
3、创建一个MANIFEST.MF文件,且这个文件的Premain-Class配置项必须设置为实现了premain方法的类的类名
4、将项目打包成jar包
5、通过java -javaagent:agent.jar demo.jar来使用jar包
实现
1、创建包含premain方法的类,一定要按照两者中的一种来实现,premain()顾名思义,会在main()方法之前执行
//agentArgs是一个字符串,会随着jvm启动设置的参数得到
//inst就是我们需要的Instrumention实例了,由JVM传入。我们可以拿到这个实例后进行各种操作
public static void premain(String agentArgs, Instrumentation inst); [1]
public static void premain(String agentArgs); [2]
2、编写一个Agent类
public class Agent
{
public static void premain(String agentArgs, Instrumentation inst){
inst.addTransformer(new MyClassTransformer(), true);
}
}
3、其中MyClassTransformer是我自定义的实现了ClassFileTransformer接口的类:
public class MyClassTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
// 相关字节码增强技术(Skywalking)中用的是ByteBuddy技术
}
}
4、创建META_INF文件夹,并创建MANIFEST.MF文件,这里有两种方式,一种是,直接自己手动创建文件夹,创建MANIFEST.MF文件,并写入以下内容
Manifest-Version: 1.0
premain-class: com.xxx.Agent # 这里这里,重点填写这个东西吗,也就是我们定义的premain类
Archiver-Version: Plexus Archiver
Built-By: xxx
Created-By: Apache Maven 3.6.0
Build-Jdk: 1.8.0_191
Skywalking中用的是第二种实现方式,在pom文件中配置,在打包的时候就会自动写入相关配置:
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>false</shadedArtifactAttached>
<createDependencyReducedPom>true</createDependencyReducedPom>
<createSourcesJar>true</createSourcesJar>
<shadeSourcesContent>true</shadeSourcesContent>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
//配置Agent premain方法所在的类
<Premain-Class>${premain.class}</Premain-Class>
<Can-Redefine-Classes>${can.redefine.classes}</Can-Redefine-Classes>
<Can-Retransform-Classes>${can.retransform.classes}</Can-Retransform-Classes>
</manifestEntries>
</transformer>
</transformers>
<artifactSet>
<excludes>
<exclude>*:gson</exclude>
<exclude>io.grpc:*</exclude>
<exclude>io.netty:*</exclude>
<exclude>io.opencensus:*</exclude>
<exclude>com.google.*:*</exclude>
<exclude>com.google.guava:guava</exclude>
<exclude>org.checkerframework:checker-compat-qual</exclude>
<exclude>org.codehaus.mojo:animal-sniffer-annotations</exclude>
<exclude>io.perfmark:*</exclude>
<exclude>org.slf4j:*</exclude>
</excludes>
</artifactSet>
<relocations>
<relocation>
<pattern>${shade.net.bytebuddy.source}</pattern>
<shadedPattern>${shade.net.bytebuddy.target}</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>net.bytebuddy:byte-buddy</artifact>
<excludes>
<exclude>META-INF/versions/9/module-info.class</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
5、打成jar包,测试