Introduction to Java agent

1、 Write in front

Java agent technology appears in jdk1 After 5, it is relatively unfamiliar to most people, but we have been in contact with it more or less. In fact, many tools we usually use are implemented based on Java agent, such as common hot deployment jrebel, various online diagnostic tools (btrace, greys), and Ari's open source Arthas.

In fact, the Java agent is not mysterious at all. It is also a jar package, but the startup method is different from the ordinary jar package. For the ordinary jar package, it is started through the main function of the specified class, but the Java agent cannot be started alone and must be attached to a Java application.

We can use agent technology to build an application independent agent to help monitor, run and even replace programs on other JVMs. It can be used to realize the AOP function at the virtual machine level.

2、 Write a Java agent

First, let's write a simple agent program:

public class AgentTest {
    /**
     * 以 vm 参数的方式载入,在 java 程序的 main 方法执行之前执行
     *
     * @param agentArgs
     * @param inst      Agent技术主要使用的 api,我们可以使用它来改变和重新定义类的行为
     */
    public static void premain(String agentArgs,Instrumentation inst) {
        System.out.println("premain start");

        System.out.println(agentArgs);
    }

    /**
     * 以 Attach 的方式载入,在 Java 程序启动后执行
     */
    public static void agentmain(String agentArgs,Instrumentation inst) {
        System.out.println("agentmain start");

        System.out.println(agentArgs);
    }
}

Because of the particularity of Java agent, some special configurations are required, such as specifying the startup class of agent, etc. In this way, you can find and run the corresponding agentmain or premain method after loading the Java agent. There are two main configuration methods: one is to use Maven assembly plugin (recommended) and the other is to use manifest.mf file.

2.1 Maven assembly plugin

          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifestEntries>
                            <Premain-Class>org.agent.AgentTest</Premain-Class>
                            <Agent-Class>org.agent.AgentTest</Agent-Class>
                            <Can-redefine-Classes>true</Can-redefine-Classes>
                            <Can-Retransform-Classes>true</Can-Retransform-Classes>
                        </manifestEntries>
                    </archive>
                </configuration>
            </plugin>

2.2 MANIFEST. MF file

Create manifest.inf in the meta-inf directory MF file:

Manifest-Version: 1.0
Agent-Class: org.agent.AgentTest
Premain-Class: org.agent.AgentTest
Can-redefine-Classes: true
Can-Retransform-Classes: true

It is worth mentioning that even if you create a new manifest MF file, you still need to configure Maven assembly plugin information, otherwise manifest MF information will be overwritten by the information generated by Maven.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifestFile>
                            src/main/resources/Meta-INF/MANIFEST.MF
                        </manifestFile>
                    </archive>
                </configuration>
            </plugin>

After configuring the above contents, run MVN assembly: single to package the jar package belonging to Java agent.

3、 Run your agent

When the Java agent program is written, how to run it? As shown above, there are two kinds of agent programs. One is the premain function, which is executed before the main program runs; One is the agentmain function, which is executed after the main program runs. There are also differences between the two agents loaded by Java:

3.1 loading before running the main program

Through the JVM parameter - javaagent: * * Jar [= test] startup, where test is the parameter of agentargs passed into premain. When the program starts, the Java agent will be loaded first and its premain method will be executed. At this time, in fact, most classes have not been loaded. At this time, bytecode modification of newly loaded classes can be realized. However, if the premain method fails to execute or throws an exception, Then the JVM will be aborted, which is a fatal problem.

3.2 loading after the main program runs

After the program is started, the Java agent is loaded through a specific means, which is the attach API of virtualmachine. This API is actually a communication bridge between JVM processes. The bottom layer communicates through socket. JVM a can send some instructions to JVM B. after receiving the instructions, B can execute the corresponding logic, For example, jstack and JPS, which are often used in the command line, are implemented based on this mechanism.

The implementation of virtualmachine is located in tools Jar.

        <dependency>
            <groupId>com.sun</groupId>
            <artifactId>tools</artifactId>
            <version>1.8</version>
            <scope>system</scope>
            <systemPath>${java.home}/../lib/tools.jar</systemPath>
        </dependency>

Because it is interprocess communication, the process using the attach API is also an independent java process. The following is a simple implementation:

    public static void main(String[] args) throws IOException,AttachNotSupportedException,AgentLoadException,AgentInitializationException {
        VirtualMachine virtualMachine = null;
        try {
            // 1100 是进程号
            virtualMachine = VirtualMachine.attach("1100");
            // 第一个参数是 agent jar包路径,第二个参数为传入 agentmain 的 args 参数
            virtualMachine.loadAgent("D:\\concurrency-0.0.1-SNAPSHOT-jar-with-dependencies.jar","test");
        } finally {
            if (virtualMachine != null) {
                virtualMachine.detach();
            }
        }

    }

Agent implementation based on Java instrument

New instrumentation features

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>