Java Agent

Java Agent是JDK 1.5后的特性,用于实现动态字节码修改和程序热更新等。它通过premain和agentmain两种启动方式与应用程序结合,前者在main方法调用前运行,后者在main方法调用后运行。创建Java Agent需定义MANIFEST.MF文件,指定入口类并打包成jar。启动时通过-javaagent参数指定jar路径和选项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介
Java Agent是JDK 1.5 以后引入的,也叫做Java代理,可以实现动态字节码修改,程序热更新,链路跟踪等功能。
Java Agent也是一个Jar包,只是启动方式和普通Jar包有所不同,对于普通的Jar包,通过指定类的main函数进行启动,但是Java Agent不能单独启动,必须依附在一个Java应用程序才能运行。

启动方式

Java Agent 有2种启动方式

1)premain: 用于应用程序启动前,其 main 方法未调用

public static void premain(String agentArgs, Instrumentation instrumentation)

使用方法

premain使用步骤如下:

  1. 定义一个MANIFEST.MF 文件,文件中必须包含 Premain-Class;
  2. 创建一个 Premain-Class 指定的类,该类必须包含 premain 方法;
  3. 将MANIFEST.MF 和 Agent 类打成 jar 包;

在执行 main 函数之前,JVM 会先运行 -javaagent 所指定Java Agent jar包内Premain-Class这个类的premain方法
通过命令行来启动代理:
     -javaagent:jarpath[=options]

2)agentmian:用于应用程序已经启动并且其 main 方法已经调用

public static void agentmain(String agentArgs, Instrumentation instrumentation)

使用方法

agentmain 使用步骤如下:

  1. 定义一个MANIFEST.MF 文件,文件中必须包含 Agent-Class;
  2. 创建一个 Agent-Class 指定的类,该类必须包含 agentmain 方法;
  3. 将MANIFEST.MF 和 Agent 类打成 jar 包;


在main方法已经调用后,过 VirtualMachine 的list方法拿到本机所有Java进程的PID。通过 attach 连接上目标PID之后,可以获得表示目标进程的vm对象,执行 loadAgent 方法,对应的Java Agent会被加载,然后会找到指定的入口类,并执行agentmain方法。

编写Java Agent程序

public class Agent
{
    private static final Logger logger = LoggerFactory.getLogger(Agent.class);

   
    public static void premain(String agentArgs, Instrumentation instrumentation)
            throws Exception
    {
        logger.info("premain is run,agentArgs={}",agentArgs);        
    }

   
    public static void agentmain(String agentArgs, Instrumentation instrumentation)
            throws Exception
    {
        logger.info("agentmain is run,agentArgs={}",agentArgs);
    }
}

pom配置插件自动生成 MANIFEST.MF

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifestEntries>
                            <Manifest-Version>1.0</Manifest-Version>
                            <!-- premain -->
                            <Premain-Class>cn.test.agent.Agent</Premain-Class>
                            <!-- agentmain -->
                            <Agent-Class>cn.test.agent.Agent</Agent-Class>
                            <Can-Redefine-Classes>true</Can-Redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                    <skip>true</skip>
                </configuration>
            </plugin>           
        </plugins>
    </build>

生成 Java Agent jar包

agent.core-1.0-SNAPSHOT.jar

Jar 包中 MANIFEST.MF 文件内容

Manifest-Version: 1.0
Premain-Class: cn.test.agent.Agent
Built-By: chy2z
Agent-Class: cn.test.agent.Agent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Created-By: Apache Maven 3.5.3
Build-Jdk: 1.8.0_151

Premain测试

编写普通java程序

public class PreMainApp
{
    private static final Logger log = LoggerFactory.getLogger(PreMainApp.class);

    /**
     * 启动程序更新代码
     * 启动参数 -javaagent:/option/agent/agent.core-1.0-SNAPSHOT.jar
     * @param args
     */
    public static void main( String[] args ) {
        log.info("agentClient is run ");
    }
}

配置jvm启动参数

Agentmain测试

编写普通java程序

public class AgentMainApp {

    private static final Logger log = LoggerFactory.getLogger(PreMainRedisPlugin.class);

    /**
     * 演示热加载
     * 程序启动之后,更新代码
     * @param args
     */
    public static void main(String[] args) {
        try {
            List<VirtualMachineDescriptor> list = VirtualMachine.list();
            for (VirtualMachineDescriptor vmd : list) {
                //遍历虚拟机找到AgentMainApp进程
                if (vmd.displayName().endsWith("AgentMainApp")) {
                    VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
                    virtualMachine.loadAgent("E:\\option\\agent\\agent.core-1.0-SNAPSHOT.jar", "AgentMainApp");
                    System.out.println("ok");
                    virtualMachine.detach();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值