JVMTI Agent for the client.
Here the record is Java Instrument Based on Agent , as well as directly on the JVMTI Agent achieve .
After JDK1.5, we can use Agent technology to build a stand-alone application-agents, to assist in monitoring, or even replace the program running on other JVM. Use it to implement a virtual machine-level AOP functionality.
Agent divided into two types, one is Agent runs before the main program, one is running after the main Agent (JDK1.6 later).
First, before the main program running agent
1. write agent programs
package before; import java.lang.instrument.Instrumentation; public class AgentApplication { public static void premain(String arg, Instrumentation instrumentation) { System.err.println("agent startup , args is " + arg); } }
2. Add MANIFEST.MF file
Path META-INF / MANIFEST.MF
Manifest-Version: 1.0 Premain-Class: before.AgentApplication Can-Redefine-Classes: true Can-Retransform-Classes: true
If using Maven compiler would not have to manually add, you can configure the pom.xml
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Premain-Class>before.AgentApplication </Premain-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
3. Run
Create a test class and compiled into class files
package com; public class Main { public static void main(String[] args) { System.out.println("123"); } }
Use the command to run
java -javaagent: .. \ mahout-1.0-SNAPSHOT.jar = abc com.Main
We can see premain method runs before the main
Second, after the main agents operating
About Dynamic The attach: https://openjdk.java.net/groups/hotspot/docs/Serviceability.html#battach
https://juejin.im/post/5b0d020d518825153f10403f
1. write agent programs
Because it is executed in the main program and then run, it means that we can obtain information about the main program is running, where we print out the class name of the main program loaded.
package after; import java.lang.instrument.Instrumentation; public class AgentApplication { public static void agentmain(String arg, Instrumentation instrumentation) { System.err.println("agent startup , args is " + arg); Class<?>[] classes = instrumentation.getAllLoadedClasses(); for (Class<?> cls : classes) { System.out.println(cls.getName()); } } }
2. Add MANIFEST.MF file
Path META-INF / MANIFEST.MF
Manifest-Version: 1.0 Agent-Class: after.AgentApplication Can-Redefine-Classes: true Can-Retransform-Classes: true
If using Maven compiler would not have to manually add, you can configure the pom.xml
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>UTF-8</encoding> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> </manifest> <manifestEntries> <Agent-Class>after.AgentApplication </Agent-Class> <Can-Redefine-Classes>true</Can-Redefine-Classes> <Can-Retransform-Classes>true</Can-Retransform-Classes> </manifestEntries> </archive> </configuration> </plugin> </plugins> </build>
3. Run
Because it is run after the program is running, we need to have a Java process, the IDE can be run directly, without using the command line.
package com; public class Main { public static void main(String[] args) throws InterruptedException { for (; ; ) { System.out.println("123"); Thread.sleep(1000); } } }
After running the program change number to view the process, here 9084
The agent program then attach to the process above program
In JAVA_HOME path com.sun.tools.attach.VirtualMachine lib / tools.jar, the message can not be found if the IDE, can manually add in tools.jar, or configure the CLASSPATH environment variable.
package com; 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 Attach { public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException { VirtualMachine vm = VirtualMachine.attach("9084"); vm.loadAgent("D:\\IDEA\\CodeLib\\jhxxb\\mahout\\target\\mahout-1.0-SNAPSHOT.jar"); } }
IDE can be run directly, after the implementation of the program back to Main Print Console
Third, using the relevant
-Javaagent which can have multiple, but if -javaagent on the back -jar, will not take effect. That is, on the back of the main agent is invalid.
如: java -javaagent: D: \ myagent-1.jar = ABC -javaagent: D: \ myagent-2.jar = DEF -jar myapp.jar -javaagent: D: \ myagent-3.jar = GHI, 其中 myagent -3.jar 是 无效 的.
Wherein premain (agentmain) There are two methods:
- public static void premain(String agentArgs, Instrumentation inst)
- public static void premain(String agentArgs)
JVM will load priority 1, 2 loaded successfully is ignored, if not 1, load 2. Load logic sun.instrument.InstrumentationImpl class:
private void loadClassAndStartAgent(String classname, String methodname, String optionsString) throws Throwable { ClassLoader mainAppLoader = ClassLoader.getSystemClassLoader(); Class<?> javaAgentClass = mainAppLoader.loadClass(classname); Method m = null; NoSuchMethodException firstExc = null; boolean twoArgAgent = false; // The agent class must have a premain or agentmain method that // has 1 or 2 arguments. We check in the following order: // // 1) declared with a signature of (String, Instrumentation) // 2) declared with a signature of (String) // 3) inherited with a signature of (String, Instrumentation) // 4) inherited with a signature of (String) // // So the declared version of either 1-arg or 2-arg always takes // primary precedence over an inherited version. After that, the // 2-arg version takes precedence over the 1-arg version. // // If no method is found then we throw the NoSuchMethodException // from the first attempt so that the exception text indicates // the lookup failed for the 2-arg method (same as JDK5.0). try { m = javaAgentClass.getDeclaredMethod(methodname, new Class<?>[]{String.class, java.lang.instrument.Instrumentation.class}); twoArgAgent = true; } catch (NoSuchMethodException x) { // remember the NoSuchMethodException firstExc = x; } if (m == null) { // now try the declared 1-arg method try { m = javaAgentClass.getDeclaredMethod(methodname, new Class<?>[]{String.class}); } catch (NoSuchMethodException x) { // ignore this exception because we'll try // two arg inheritance next } } if (m == null) { // now try the inherited 2-arg method try { m = javaAgentClass.getMethod(methodname, new Class<?>[]{String.class, java.lang.instrument.Instrumentation.class}); twoArgAgent = true; } catch (NoSuchMethodException x) { // ignore this exception because we'll try // one arg inheritance next } } if (m == null) { // finally try the inherited 1-arg method try { m = javaAgentClass.getMethod(methodname, new Class<?>[]{String.class}); } catch (NoSuchMethodException x) { // none of the methods exists so we throw the // first NoSuchMethodException as per 5.0 throw firstExc; } } // the premain method should not be required to be public, // make it accessible so we can call it // Note: The spec says the following: // The agent class must implement a public static premain method... setAccessible(m, true); // invoke the 1 or 2-arg method if (twoArgAgent) { m.invoke(null, new Object[]{optionsString, this}); } else { m.invoke(null, new Object[]{optionsString}); } // don't let others access a non-public premain method setAccessible(m, false); }
Instrument premain, agentmain method performs timing:
premain execution timing: When the JVM starts (all Java classes are not initialized, all object instances are not created), calls the initialization function eventHandlerVMinit loadClassAndCallPremain method sun.instrument.instrumentationImpl class to perform Premain-Class specified class premain method.
agentmain execution timing: after JVM startup, by attaching a VirtualMachine Instrument, such as: vm.loadAgent (jar), the method calls loadClassAndCallAgentmain sun.instrument.instrumentationImpl class to perform the method Agentmain-Class agentmain specified class.
premain, agentmain two process parameters:
agentArgs: Agent command line input parameters, along with "-javaagent" passed together with the main function is different is that this argument is a string rather than an array of strings.
inst: java.lang.instrument.Instrumentation example, automatically imported from the JVM, concentrated almost all the features, such as: type of operation, classpath operation.
META-INF / MAINFEST.MF parameters:
- Premain-Class: class name is specified method comprising premain.
- Agent-Class: class name is specified method comprising agentmain.
- Boot-Class-Path: Specifies the path list search boot class loader. Find the characteristics of the class after the failure mechanism of the platform, the bootstrap class loader will search these paths.
- Can-Redefine-Class: Can redefine classes needed by this agent, the default is false.
- Can-Retransform-Class: whether to re-convert the classes needed by this agent, the default is false.
- Can-Set-Native-Method-Prefix: whether this agent can set the desired native method prefix, default is false.
https://www.jianshu.com/p/63c328ca208d
https://yq.aliyun.com/articles/658806
https://www.jianshu.com/p/9f4e8dcb3e2f