Java Agent(java probe) has existed since jdk1.5, but for most business development javaer s, it is still quite magical and strange; although in actual business development, agent development is rarely involved, but every java development has been used, such as using idea to write a HelloWorld.java, and running it, and looking at the console output carefully
As an introduction to Java Agent, this article will teach you how to develop a Java Agent with time-consuming statistical methods
<!-- more -->
1. Java agent development
First of all, define our development environment, choose IDEA as editor, maven for package management
1. Core logic
Create a new project (or sub module), and then we create a new SimpleAgent class
public class SimpleAgent { /** * jvm Start in parameter form, run this method * * @param agentArgs * @param inst */ public static void premain(String agentArgs, Instrumentation inst) { System.out.println("premain"); } /** * Start in dynamic attach mode, run this method * * @param agentArgs * @param inst */ public static void agentmain(String agentArgs, Instrumentation inst) { System.out.println("agentmain"); } }
Let's ignore the specific play methods of the above two methods. First, let's have a brief look at the differences between the two methods. The notes also say that
- jvm parameter form: call premain method
- attach method: call the agentmain method
The jvm mode, that is to say, to use the target application of this agent, when starting, you need to specify the jvm parameter - javaagent:xxx.jar, which can be used when the agent we provide belongs to the basic essential service
When the target application starts, we do not add Java agent to load our agent, but still hope that the target program uses our agent. At this time, we can use the attach method (the specific usage posture will be introduced later). Naturally, we will think that if our agent is used to debug and locate problems, we can use this method
2. pack
The above simple Agent has finished the core functions of our Agent (that is, it is so simple). Next, we need to print a Jar package
Through the maven plug-in, you can simply output a compliant java agent package. There are two common usage gestures
a. pom specified configuration
In the pom.xml file, add the following configuration, note the parameters in the manifest entries tab
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifestEntries> <Premain-Class>com.git.hui.agent.SimpleAgent</Premain-Class> <Agent-Class>com.git.hui.agent.SimpleAgent</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> <executions> <execution> <goals> <goal>attached</goal> </goals> <phase>package</phase> </execution> </executions> </plugin> </plugins> </build>
Then, we use the mvn assembly:assembly command to package. In the target directory, we can see a jar package with the suffix of jar with dependencies, which is our target
b. MANIFEST.MF configuration file
It may be more common through the configuration file MANIFEST.MF. Here is a brief introduction to using poses
- Under resources, create a new directory META-INF
- In the META-INF directory, create a new file, MANIFEST.MF
The contents of the document are as follows
Manifest-Version: 1.0 Premain-Class: com.git.hui.agent.SimpleAgent Agent-Class: com.git.hui.agent.SimpleAgent Can-Redefine-Classes: true Can-Retransform-Classes: true
Please note that the last blank line (if I don't show it above, it's mostly a mark down rendering problem), can't be less. In idea, when deleting the last line, there will be an error reminder
Then our pom.xml configuration needs to be modified accordingly
<build> <plugins> <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> <!--<manifestEntries>--> <!--<Premain-Class>com.git.hui.agent.SimpleAgent</Premain-Class>--> <!--<Agent-Class>com.git.hui.agent.SimpleAgent</Agent-Class>--> <!--<Can-Redefine-Classes>true</Can-Redefine-Classes>--> <!--<Can-Retransform-Classes>true</Can-Retransform-Classes>--> <!--</manifestEntries>--> </archive> </configuration> <executions> <execution> <goals> <goal>attached</goal> </goals> <phase>package</phase> </execution> </executions> </plugin> </plugins> </build>
Also packaged with the mvn assembly:assembly command
2. Agent usage
Agent has it. Next, we need to test the use of agent. The above two methods are proposed, and we will explain them separately
1. jvm parameters
First, create a demo project and write a simple test class
public class BaseMain { public int print(int i) { System.out.println("i: " + i); return i + 2; } public void run() { int i = 1; while (true) { i = print(i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { BaseMain main = new BaseMain(); main.run(); Thread.sleep(1000 * 60 * 60); } }
In the test class, there is a dead cycle. Each 1s calls the print method. During the IDEA test, you can directly configure the class and add the jvm parameters, as follows
Please note that the content in the red box above is the absolute address of the agent packaged in the previous section: - javaagent: / users /.. / target / java-agent-1.0-snapshot-jar-with-dependencies.jar
After executing the main method, you will see the console output
Please note the premain above. This is the output of the premain method in our SimpleAgent above, and it is only output once
2. attach mode
When using attach mode, it can be simply understood that we want to inject our agent into the target application, so we need to start a program ourselves to accomplish this
public class AttachMain { public static void main(String[] args) throws IOException, AgentLoadException, AgentInitializationException, AttachNotSupportedException { // The attach method parameter is the process number of the target application VirtualMachine vm = VirtualMachine.attach("36633"); // Please replace this with your own agent absolute address vm.loadAgent("/Users/......./target/java-agent-1.0-SNAPSHOT-jar-with-dependencies.jar"); } }
The above logic is relatively simple. First, get the process number of the target application through jps-l
When the main method above is completed, the console will output two lines of logs similar to the following. It can be simply understood that I connected to the target application, lost an agent, and left without taking any clouds with a wave of sleeves
Connected to the target VM, address: '127.0.0.1:63710', transport: 'socket' Disconnected from the target VM, address: '127.0.0.1:63710', transport: 'socket'
Next, take a look at the output of BaseMain above. A line of agentmain is sandwiched in the middle, indicating that the agent has been successfully injected
3. summary
This paper introduces the whole process of developing and packaging a Java agent of hello world under the environment of maven + idea
Two methods
Method | Explain | Using posture |
---|---|---|
premain() | Called when the agent is loaded in jvm mode, that is, when the target application is started, the agent is specified | -javaagent:xxx.jar |
agentmain() | Called when the agent is running in attach mode and used when the target application is working normally | VirtualMachine.attach(pid) to specify the target process number < br / > vm.loadagent ("... Jar") load agent |
Two packing postures
When packaging as an available java agent, you need to pay attention to the configuration parameters. There are two ways provided above. One is to specify the configuration directly in pom.xml
<manifestEntries> <Premain-Class>com.git.hui.agent.SimpleAgent</Premain-Class> <Agent-Class>com.git.hui.agent.SimpleAgent</Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries>
The other is written in the configuration file META-INF/MANIFEST.MF (note that the last blank line is indispensable)
Manifest-Version: 1.0 Premain-Class: com.git.hui.agent.SimpleAgent Agent-Class: com.git.hui.agent.SimpleAgent Can-Redefine-Classes: true Can-Retransform-Classes: true
Of course, after reading the content of this article, you will find that the actual development of java agent is still unclear. Is agent just outputting a line of hello world in the front, which is totally different from what you think
In the next blog, I will teach you how to implement a java agent package with time-consuming method statistics. I will explain in detail how to use the interface Instrumentation to implement bytecode modification, so as to realize function enhancement
II. other
0. source code
1. A grey Blog: https://liuyueyi.github.io/hexblog
A grey personal blog, recording all the learning and working blog, welcome to visit
2. statement
The best letter is not as good as the above. It's just a one-of-a-kind remark. Due to my limited ability, there are inevitably omissions and mistakes. If you find a bug or have better suggestions, you are welcome to criticize and correct. Thank you very much
- Microblog address: Little ash Blog
- QQ: Yihui / 3302797840
3. Scanning attention
A grey blog