如何编写一个javaAgent jar工具包超详细教程

介绍

Java Agent技术

Java Agent技术是JDK提供的用来编写Java工具的技术,使用这种技术生成一种特殊的jar包,这种jar包可以让Java程序

运行其中的代码。

Java Agent技术的两种模式

Java Agent技术实现了让Java程序执行独立的Java Agent程序中的代码,执行方式有两种:

⚫ 静态加载模式

⚫ 动态加载模式

Java Agent技术的两种模式 - 静态加载模式

静态加载模式可以在程序启动的一开始就执行我们需要执行的代码,适合用APM等性能监测系统从一开始就监控程序

的执行性能。静态加载模式需要在Java Agent的项目中编写一个premain的方法,并打包成jar包。

接下来使用以下命令启动Java程序,此时Java虚拟机将会加载agent中的代码并执行

premain方法会在主线程中执行:

Java Agent技术的两种模式 -- 动态加载模式

动态加载模式可以随时让java agent代码执行,适用于Arthas等诊断系统。动态加载模式需要在Java Agent的项目中编

写一个agentmain的方法,并打包成jar包

接下来使用以下代码就可以让java agent代码在指定的java进程中执行了。

agentmain方法会在独立线程中执行:

搭建java agent静态加载模式的环境

步骤:

1、创建maven项目,添加maven-assembly-plugin插件,此插件可以打包出java agent的jar包。

2、编写类和premain方法,premain方法中打印一行信息。

3、编写MANIFEST.MF文件,此文件主要用于描述java agent的配置属性,比如使用哪一个类的

premain方法。

4、使用maven-assembly-plugin进行打包。

5、创建spring boot应用,并静态加载上一步打包完的java agent。

步骤1-4

代码(使用jdk17编辑):

目录结构:

maven 项目 pom.xml 文件(关注代码点插件位置)

java 复制代码
<?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>org.example</groupId>
    <artifactId>itheima-agent</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
<build>
    <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <!--将所有依赖都打入同一个jar包中-->
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <!--指定java agent相关配置文件-->
                     <archive>
                         <manifestFile>src/main/resources/MANIFEST.MF</manifestFile>
                     </archive>
                </configuration>
            </plugin>
    </plugins>
</build>

</project>

AgenMain.java

java 复制代码
package com.zss.javaagent;

import java.lang.instrument.Instrumentation;

public class AgenMain {
    // premain方法
    public static void premain(String agentArgs, Instrumentation inst){
        System.out.println("【remain执行了】");
    }
    // premain方法
    public static void agentmain(String agentArgs, Instrumentation inst){
        System.out.println("【agentmain执行了】");
    }
}

MANIFEST.MF

java 复制代码
Manifest-Version: 1.0
Premain-Class: com.zss.javaagent.AgenMain
Agent-Class: com.zss.javaagent.AgenMain
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Can-Set-Native-Method-Prefix: true

进行打包

步骤5:

创建springboot项目

JavaAgentTestController.java

java 复制代码
package com.example.testdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * java -jar -javaagent:D:/jvm/itheima-jvm-java-agent-jar-with-dependencies.jar  .\spring-boot-demo-0.0.1-SNAPSHOT.jar
 */
@RestController
@Controller
public class JavaAgentTestController {

    @GetMapping("/test1")
    public String test1(String name) {
        return "test1";
    }
}

TestdemoApplication.java

java 复制代码
package com.example.testdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.nio.ByteBuffer;

@SpringBootApplication
public class TestdemoApplication {

    public static void main(String[] args) {
        System.out.println("main方法执行了...");
        SpringApplication.run(TestdemoApplication.class, args);
    }

}

pom文件中我只添加了这个依赖

xml 复制代码
  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

打包操作

启动jar包

java 复制代码
java -jar .\testdemo-0.0.1-SNAPSHOT.jar

此时日志只显示main方法执行了...

退出程序 Ctrl+c

如何启动jar包之前启动agent连接到jar包呢(需要再通过java agent命令将jar包引入进来)

右键复制刚才agent jar包的绝对路径

可以发现已经打印出了agent包里面写的方法了

命令:

java 复制代码
java -jar -javaagent:E:\IEDA_DEMO\Study\jvm\javaagent\itheima-agent\target\itheima-agent-1.0-SNAPSHOT-jar-with-dependencies.jar  .\testdemo-0.0.1-SNAPSHOT.jar

上面是操作agent静态加载到jar包当中,下面我们来看看动态加载

搭建java agent动态加载模式的环境

步骤:

1、创建maven项目,添加maven-assembly-plugin插件,此插件可以打包出java agent的jar包。

2、编写类和agentmain方法, agentmain方法中打印一行信息。

3、编写MANIFEST.MF文件,此文件主要用于描述java agent的配置属性,比如使用哪一个类的

agentmain方法。

4、使用maven-assembly-plugin进行打包。

5、编写main方法,动态连接到运行中的java程序。

首先刚才的启动springboot项目

打开cmd 使用jps 插看当前springboot程序的进程ID记录下来

进程ID为:28712

新建一个类为:AttachMain.java 将刚才查看的进程ID复制到

下面这段代码里,另一个需要填写的则是agent jar包的绝对路径

java 复制代码
package com.zss.javaagent;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

import java.io.IOException;

public class AttachMain {
    public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
        //获取进程虚拟机对象  
        VirtualMachine attach = VirtualMachine.attach("28712");
          // 执行 java agent 里面的agentmain 方法(所以需要找到jar包的路径)
        attach.loadAgent("E:\\IEDA_DEMO\\Study\\jvm\\javaagent\\itheima-agent\\target\\itheima-agent-1.0-SNAPSHOT-jar-with-dependencies.jar");
     }
}

执行下main方法试试

这个项目扫描都没有输出(因为这个链接的进程是隔壁springboot项目可以去隔壁看看)

执行五次看看

是不是有点arthas连接已运行的程序并执行代码的味道了。

相关推荐
树若逝花若殇3 分钟前
基于Spring AOP优雅记录请求响应日志
java·spring boot
Yyyyyy~29 分钟前
【java】数组的定义和使用
java
麻辣布丁30 分钟前
java集合篇面试模拟
java·开发语言·面试
niucloud-admin32 分钟前
JAVA V6 多商户商城 开发文档——插件开发规范
java·开发语言
嘟哩DuliDuli44 分钟前
创作 Agent 的任务状态该如何保存
android·java·javascript
wdfk_prog1 小时前
lely-canopen-rtt:为什么推荐在 RT-Thread 上使用 Lely CANopen 构建主站
java·运维·缓存·docker·容器
Token掘金室1 小时前
JSON模式结构化输出报错
java·服务器·json
秋饼1 小时前
Spring AI 2.0 接入 DeepSeek V4.1 Flash 生产级实战
java·ai·技术分享·后端开发
IT枫斗者枫哥1 小时前
Java 分批导出仍然 OOM?用 32 MiB 堆复现三种 CSV 写法
java
shehuiyuelaiyuehao1 小时前
算法43,外观数列,模拟算法+双指针
java·算法