
简单来说, javaagent 是在class 被装在到ClassLoader之前对其拦截,插入自定义的监听字节码,可实现零侵入的监控,是APM的核心技术
Java1.5之后引入的特性
JavaAgent 运行在 main方法之前 ,内置的方法名为premain,即先执行premain方法,然后再执行main方法。通过premain方法,可实现一个JavaAgent。
javaagent 应用场景:监控、代码覆盖率分析 、JProfiler、应用破解等等等
javaagent 其实就是一个jar 包,通过-javaagent:xxx.jar 引入监控目标应用。那这个jar 和普通的jar 的区别在哪里呢?
我们来先看个结论

maven搭建 编译
<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.0modelVersion>
<groupId>com.artisangroupId>
<artifactId>javaagentartifactId>
<version>1.0-SNAPSHOTversion>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-jar-pluginartifactId>
<version>2.2version>
<configuration>
<archive>
<manifestEntries>
<Project-name>${project.name}Project-name>
<Project-version>${project.version}Project-version>
<Premain-Class>com.artisan.ssist.JavaAgentDemoPremain-Class>
<Boot-Class-Path>javassist-3.18.1-GA.jarBoot-Class-Path>
<Can-Redefine-Classes>falseCan-Redefine-Classes>
manifestEntries>
archive>
<skip>trueskip>
configuration>
plugin>
plugins>
build>
<dependencies>
<dependency>
<groupId>org.javassistgroupId>
<artifactId>javassistartifactId>
<version>3.18.1-GAversion>
dependency>
dependencies>
project>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");
}
}
点击 M, 执行 mvn clean package

查看jar包中的 MANIFEST.MF文件 , MANIFEST.MF文件用于描述Jar包的信息,例如指定入口函数等。

jvm参数指定
-javaagent:E:\IdeaProjects\javaagent\target\javaagent-1.0-SNAPSHOT.jar
执行,观察我们引入的这个jar包中的premain方法是否优先于这个测试类的main方法执行

OK ,这个就是Java Agent的 简单小栗子, 更强大的功能继续开篇


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();
}总结
开启参数

agent 依懒包逗号分割
Boot-Class-Path: javassist-3.18.1-GA.jar
是否允许重定义
Can-Redefine-Classes: true
允许重载
Can-Retransform-Classes:true既然是搞字节码,有没有类库 ?
其实上面的栗子 其实已经使用了Javassist 类库了~
Javassist是一个开源的分析、编辑和创建Java字节码的类库。
关于java字节码的处理, 目前有很多开源工具可用,比如asm,bcel, 不过这些都需要直接跟虚拟机指令打交道,实在是太难。。。。。
如果不想了解虚拟机指令,可以采用javassist。
javassist是jboss的一个子项目,优点简单 快速 ,直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。