# java-agent-demo **Repository Path**: adherent996/java-agent-demo ## Basic Information - **Project Name**: java-agent-demo - **Description**: java agent 使用样例 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-07-23 - **Last Updated**: 2024-07-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README **含义:** Java Agent 是 Java 编程语言提供的一种特殊机制,允许你在程序运行过程中对字节码进行转换和增强。它是通过 Java 的 Instrumentation API 来实现的,可以用于在应用程序加载类时进行监测、修改和增强。 Java Agent 通常被用于实现 性能监控、日志记录、代码分析、方法耗时统计、系统调试、字节码增强等。 java agent本质上可以理解为一个插件,该插件就是一个精心提供的jar包,这个jar包通过JVMTI(JVM Tool Interface)完成加载,最终借助JPLISAgent(Java Programming Language Instrumentation Services Agent)完成对目标代码的修改。 java agent技术进行类的字节码修改最主要使用的就是Java Instrumentation API。 Instrument是JVM提供的一个可以修改已加载类的类库,专门为Java语言编写的插桩服务提供支持。它需要依赖JVMTI的Attach API机制实现。 在JDK 1.6以前,Instrument只能在JVM刚启动开始加载类时生效,而在JDK 1.6之后,instrument支持了在运行时对类定义的修改。 要使用Instrument的类修改功能,我们需要实现它提供的 ClassFileTransformer 接口,定义一个类文件转换器。 接口中的transform()方法会在类文件被加载或者重载时调用,而在transform方法里,我们可以利用上文中的ASM或Javassist对传入的字节码进行改写或替换,生成新的字节码数组后返回。 java agent技术的主要功能如下: - 可以在加载java文件之前做拦截把字节码做修改: - 可以在运行期将已经加载的类的字节码做变更: - 还有其他的一些小众的功能: - 获取所有已经被加载过的类 - 获取所有已经被初始化过了的类 - 获取某个对象的大小 - 将某个jar加入到bootstrapclasspath里作为高优先级被bootstrapClassloader加载 - 将某个jar加入到classpath里供AppClassloard去加载 - 设置某些native方法的前缀,主要在查找native方法的时候做规则匹配 **Java Agent 的主要特点:** - 动态性: Java Agent 允许你在程序运行时加载类,对类进行转换和增强,从而实现动态修改已编译类的功能。 - 无侵入性: 使用 Java Agent 不需要修改源代码,也不需要重新编译。这使得你可以在不改变程序结构的情况下,实现一些横切关注点的逻辑。 - 全局性: Java Agent 可以在整个 JVM 中生效,对加载的所有类都可以进行转换和增强。这使得你可以监测、分析和增强全局的应用行为。 **Java Agent主要分为两类:** 1. 启动时加载的Agent(Pre-Main Agent): 这种类型的Agent在应用程序的主方法(main)执行之前加载。它们通常用于在应用程序启动时进行一些预处理,例如初始化日志框架、植入一些监控代码等。 2. 运行时加载的Agent(Agent-On-Load) 这种Agent可以在JVM运行时动态加载和附加,通常用于对正在运行的应用程序进行监控和修改。 1. 启动时加载的Agent(Pre-Main Agent)的编写通常需要遵循以下步骤: - 创建转换类: 创建一个转换类,实现 ClassFileTransformer 接口的 transform 方法,在其内部编写转换逻辑。 - 注册类: 创建一个类在内部编写 premain 方法,然后在 premain方法中 使用 Instrumentation API 注册转换类。这将使转换类在 JVM 启动时加载并执行。 MANIFEST.MF文件: ```manifest ## 文件版本 Manifest-Version: 1.0 # 包含 premain 方法的类(类的全路径名), main方法运行前代理 Premain-Class: com.zf.agentdefine.RegisterAgent # 包含 agentmain 方法的类(类的全路径名),运行时代理 Agent-Class: com.zf.agentdefine.RegisterAgent # 能够重定义类 Can-Redefine-Classes: true # 能够重转换类 Can-Retransform-Classes: true ``` 使用 `-javaagent:jar路径` 参数 在启动时加载编写好的agent