Java Agent

简介
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


        
            
                org.apache.maven.plugins
                maven-jar-plugin
                
                    
                        
                            1.0
                            
                            cn.test.agent.Agent
                            
                            cn.test.agent.Agent
                            true
                            true
                        
                    
                    true
                
                       
        
    

生成 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启动参数

Java Agent_第1张图片

Agentmain测试

编写普通java程序

public class AgentMainApp {

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

    /**
     * 演示热加载
     * 程序启动之后,更新代码
     * @param args
     */
    public static void main(String[] args) {
        try {
            List 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();
        } 
    }
}

 

你可能感兴趣的:(字节码)