APM - Hello Javaagent
什么是javaagent
简单来说, javaagent 是在class 被装在到ClassLoader之前对其拦截,插入自定义的监听字节码,可实现零侵入的监控,是APM的核心技术
Java1.5之后引入的特性
JavaAgent 运行在 main方法之前 ,内置的方法名为premain,即先执行premain方法,然后再执行main方法。通过premain方法,可实现一个JavaAgent。
javaagent 应用场景:监控、代码覆盖率分析 、JProfiler、应用破解等等等
javaagent的jar包 和 普通jar包的区别
javaagent 其实就是一个jar 包,通过-javaagent:xxx.jar 引入监控目标应用。那这个jar 和普通的jar 的区别在哪里呢?
我们来先看个结论
从零搭建第一个javaagent
maven搭建 编译
【pom.xml】
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.artisan</groupId>
<artifactId>javaagent</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.2</version>
<configuration>
<archive>
<manifestEntries>
<Project-name>${project.name}</Project-name>
<Project-version>${project.version}</Project-version>
<Premain-Class>com.artisan.ssist.JavaAgentDemo</Premain-Class>
<Boot-Class-Path>javassist-3.18.1-GA.jar</Boot-Class-Path>
<Can-Redefine-Classes>false</Can-Redefine-Classes>
</manifestEntries>
</archive>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.18.1-GA</version>
</dependency>
</dependencies>
</project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- Premain-Class:指定包含 premain 方法的类名 ,改成自己的类
- Can-Redefine-Class:是否能重新定义此代理所需的类,默认为 false。
【Agent Code】
package com.artisan.ssist;
import java.lang.instrument.Instrumentation;
public class JavaAgentDemo {
public static void premain(String args ,Instrumentation instrumentation){
System.out.println("premain first agent demo");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
【编译成jar】
点击 M, 执行 mvn clean package
查看jar包中的 MANIFEST.MF文件 , MANIFEST.MF文件用于描述Jar包的信息,例如指定入口函数等。
【引入agent jar 为当前应用启动前插入premain逻辑】
jvm参数指定
-javaagent:E:\IdeaProjects\javaagent\target\javaagent-1.0-SNAPSHOT.jar
- 1
执行,观察我们引入的这个jar包中的premain方法是否优先于这个测试类的main方法执行
OK ,这个就是Java Agent的 简单小栗子, 更强大的功能继续开篇
javaagent 流程示意图
进阶Demo
public class AgentMain {
public static void premain(String args, Instrumentation instrumentation)
throws Exception, ClassNotFoundException {
// 实例化对象
UserService userService = new UserService();
// 类比ClassLoader
ClassPool classPool = new ClassPool();
// 追加系统ClassLoader
classPool.appendSystemPath();
// 获取一个类
CtClass ctClass = classPool.get("com.artisan.agent.UserService");
// 获取方法
CtMethod sayHello = ctClass.getDeclaredMethod("sayHello");
// 在方法执行之后插入下面这行语句
sayHello.insertAfter("System.out.println(\"I am fine\");");
// 重新定义一个类
instrumentation.redefineClasses(new ClassDefinition(UserService.class,ctClass.toBytecode()));
// 调用服务 这里的userservice 已经是被重新定义的 对象了
userService.sayHello();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
总结
- 1.instrumentation addTransformer 类装载拦截
- 2.只能拦截未装载过的类
- 3.instrumentation#retransformClasses方法 重新装载类 ,必须开启相关参数
- 4.instrumentation.redefineClasses 重新定义一个类 ,不能添加新方法 ,必须开启相关参数
开启参数
agent 依懒包逗号分割
Boot-Class-Path: javassist-3.18.1-GA.jar
是否允许重定义
Can-Redefine-Classes: true
允许重载
Can-Retransform-Classes:true
- 1
- 2
- 3
- 4
- 5
- 6
- 7
Javassist 引入
既然是搞字节码,有没有类库 ?
其实上面的栗子 其实已经使用了Javassist 类库了~
Javassist是一个开源的分析、编辑和创建Java字节码的类库。
关于java字节码的处理, 目前有很多开源工具可用,比如asm,bcel, 不过这些都需要直接跟虚拟机指令打交道,实在是太难。。。。。
如果不想了解虚拟机指令,可以采用javassist。
javassist是jboss的一个子项目,优点简单 快速 ,直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。
原文链接:artisan.blog.csdn.net/article/details/107379611
- 点赞
- 收藏
- 关注作者
评论(0)