1),如何实现代码增强
java agent
Skywallking监控JVM主要使用java agent
(ps: java agent可以在不修改目标应用达到代码增强的目的,就好像spring的aop一样,但是java agent是直接修改字节码,而不是通过创建代理类。例如skywalking就是使用java agent技术,为目标应用代码植入监控代码,监控代码进行数据统计上报的。这种方式实现了解耦,通用的功能)
Java agent 实现非常简单我们只需要定义一个类,然后类中定义一个方法名为premain 的方法,然后在MANIFEST.MF 文件中添加以下内容:
Manifest-Version: 1.0
Agent-Class: org.agent.AgentTest
Premain-Class: org.agent.AgentTest
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain 有两种实现方式,区别在于选择带有Instrumentation参数,可以使用该变量完成代码的热替换
public class DemoAgent {
/**
* 该方法在main方法之前运行,与main方法运行在同一个JVM中
*/
public static void premain(String arg, Instrumentation instrumentation) {
System.out.println("agent的premain(String arg, Instrumentation instrumentation)方法");
// instrumentation.addTransformer();
}
/**
* 若不存在 premain(String agentArgs, Instrumentation inst),
* 则会执行 premain(String agentArgs)
*/
public static void premain(String arg) {
System.out.println("agent的premain(String arg)方法");
}
Bytebuddy
Byte Buddy是一个字节码生成和操作库,用于在Java应用程序运行时创建和修改Java类,而无需编译器的帮助。除了Java类库附带的代码生成实用程序外,Byte Buddy还允许创建任意类,并且不限于实现用于创建运行时代理的接口。此外,Byte Buddy提供了一种方便的API,可以使用Java代理或在构建过程中手动更改类。
• 无需理解字节码指令,即可使用简单的 API 就能很容易操作字节码,控制类和方法。
• 已支持Java 11,库轻量,仅取决于Java字节代码解析器库ASM的访问者API,它本身不需要任何其他依赖项。
• 比起JDK动态代理、cglib、Javassist,Byte Buddy在性能上具有一定的优势。
附maven依赖
<dependencies>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>LATEST</version>
</dependency>
</dependencies>
<build>
<!-- <resources>
<resource>
<!– 设定主资源目录 –>
<directory>src</directory>
</resource>
</resources>-->
<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>
<!-- 包含premain方法的类 -->
<Premain-Class>com.dyb.agent.DemoAgent</Premain-Class>
<!-- 对目标类字节码操作权限 -->
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<!-- 对目标类字节码操作权限 -->
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>