Java- based Instrument's Agent

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:

  1. public static void premain(String agentArgs, Instrumentation inst)
  2. 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);
}
View Code

 

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

https://juejin.im/post/5b0925ec51882538aa1ee248

https://www.ibm.com/developerworks/cn/java/j-lo-jpda2

Guess you like

Origin www.cnblogs.com/jhxxb/p/11567337.html