The previous permain method can only be executed before the Java program is started, not after the program is started. However, in many cases, there is no way to delegate the virtual machine when it is started, which effectively limits the use of instrument. The new Java SE 6 feature changes that by attaching in the Java Tool API, you can set up the proxy after the application is started.

The Attach API is not a standard Java API, but an extended set of APIS provided by Sun for “attaching” proxy applications to target JVMS. With it, developers can easily monitor a JVM and run an additional agent.

The Attach API is simple, with only two main classes, both in the com.sun.tools. Attach package: VirtualMachine represents a Java VirtualMachine, the target VirtualMachine that the program needs to monitor, providing JVM enumerations, Attach actions and Detach actions (removing an agent from the JVM), and so on. VirtualMachineDescriptor is a container class that describes virtual machines, and implements various functions with the VirtualMachine class.

Combine the previous article with Attach to see how to use

Add two agentMain () methods to the Agent class. Their parameters are not used. The priority of two parameters is greater than one parameter, so only agentMain (String agentArgs, Instrumentation Inst) can be executed

public class JpAgent {

    public static void premain(String agentArgs){
        System.out.println("I am a Java Agent premain with one parameter");
    }

    public static void agentmain (String agentArgs, Instrumentation inst) throws UnmodifiableClassException {
        inst.addTransformer(new JpClassFileTransformerDemo(), true); // retransformClasses is a new method in Java SE 6 that, like redefineClasses, can convert inst.retransformclasses (dog.class) in bulk; System.out.println("I'm a Two-parameter Java Agent Agentmain");

    }
    public static void agentmain (String agentArgs){
        System.out.println("I am a parameter of Java Agent Agentmain"); }}Copy the code

Add a new Dog class with the following contents, the key point being that the package path should be the same as the target program, and nothing else

package cn.jpsite.learning;

public class Dog {
}
Copy the code

In the previous example01 project, create a new class whilemain.java with the main function

public class WhileMain {
    public static void main(String[] args) throws InterruptedException {
        System.out.println(new Dog().say());
        int count = 0;
        while (trueThread.sleep(500); count++; String say = new Dog().say(); System.out.println(say + count); // The content is incorrect or the number of output exceeds 1000 timesif (!"dog".equals(say) || count >= 1000) {
                System.out.println("Someone stole my dog!");
                //break; }}}}Copy the code

Prepare a modified dog. class with the following contents and save it separately to the directory D:\learning\ dog. class

// This is a modified.class file, which contains a separate public class Dog {public Stringsay() {
        return "cat"; }}Copy the code

Resource/meta-INF/manifest.mf New content

Agent-Class: cn.jpsite.learning.javaagent01.JpAgent
Can-Retransform-Classes: true
Copy the code

At this point, the preparation is almost complete and the packaged build is executed. Executing either of the following will result in no agentMain output

Jar -cp example01-1.0-snapshot.jar cn.jpsite.learning.Main Java-javaAgent: jpagent.jar -cp Example01-1.0 - the SNAPSHOT. Jar cn. Jpsite. Learning. WhileMain Java - cp example01-1.0 - the SNAPSHOT. Jar cn. Jpsite. Learning. WhileMainCopy the code

What if the result is that agentMain is not called?

Com.sun.tools. attach will be used to help us achieve the agent Settings after vm startup. The code is as follows:

import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; import java.io.IOException; import java.util.List; import java.util.Objects; /** ** @author Jiangpeng * @date 2019/12/10001 */ public class AttachThread extends Thread {/** * Record the VM set at startup */ private final List<VirtualMachineDescriptor> listBefore; /** Private final String jar; private AttachThread(String attachJar, List<VirtualMachineDescriptor> vms) { listBefore = vms; jar = attachJar; } @Override public voidrun() {
        VirtualMachine vm;
        List<VirtualMachineDescriptor> listAfter;
        int count = 0;

        try {
            while (true) {
                listAfter = VirtualMachine.list();
                vm = hasNewVm(listAfter);

                if(vm == null){
                    System.out.println("No new JVM program, please manually specify Java PID");
                    try{
                        vm = VirtualMachine.attach("7716");
                    }catch (AttachNotSupportedException e){
                        //System.out.println("Refused access Disconnected from the target VM");
                    }
                }

                Thread.sleep(1000);
                System.out.println(count++);
                if(null ! = vm || count >= 100) {break;
                }
            }
            Objects.requireNonNull(vm).loadAgent(jar);
            vm.detach();
        } catch (Exception e) {
            System.out.println("Exception:"+ e); }} /** * Check whether a new JVM program is running */ private VirtualMachine hasNewVm(List<VirtualMachineDescriptor> listAfter) throws IOException, AttachNotSupportedException {for (VirtualMachineDescriptor vmd : listAfter) {
            if(! Listbefore.contains (VMD)) {// If the VM is added, we start monitoring the VM system.out.println (listbefore.contains (VMD)) {// If the VM is added, we start monitoring the VM system.out.println ("There are new VM programs:"+ vmd.displayName());
                returnVirtualMachine.attach(vmd); }}return null;
    }

    public static void main(String[] args)  {
        new AttachThread("D:/learning/jpAgent.jar", VirtualMachine.list()).start(); }}Copy the code

The while loop gets the Java process collection every second. If it doesn’t, it prompts you to manually attach a Java program. After 100 loops or VirtualMachine is acquired, Exit while(true) to load the specified agent.jar.

Two test methods

To execute Java – cp example01-1.0 – the SNAPSHOT. Jar cn. Jpsite. Learning. WhileMain start example01 program, see the following result, remember before we prepared a t the class, Say () is cat, and you’ll see something magical later

jps -l

Modify VirtualMachine. Attach (“7716″) in AttachThread. The code for the VirtualMachine. Attach (” 16304 “); 16304 is the WhileMain Java process ID in the figure above. Restart attachThread. Java

loader className: cn/jpsite/learning/Dog

I am the Java Agent AgentMain with two parameters

You can see that agentMain has been executed and the original dog.say () method Dog has been changed to cat

The second,

First start the AttachThread. Java, then execute the Java – cp example01-1.0 – the SNAPSHOT. Jar cn. Jpsite. Learning. WhileMain, can see the results soon be changed

Other properties of manifest.mf

Can-Set-Native-Method-Prefix
System-Class-Path
Boot-Class-Path
Copy the code

New in Java SE 6: Dynamic add-on to BootClassPath/SystemClassPath

Notice a couple of things. First, the JAR files we add to the classpath should not have any system namesake classes related to the instrumentation of the system, otherwise everything will fall into unpredictability

Note how the virtual machine’s ClassLoader works, which logs the parsing results. For example, if we asked to read some someclass and failed, the ClassLoader will remember that. Even if we later dynamically add a JAR containing the class, the ClassLoader will still assume that we cannot parse the class, and the same error as the last one will be reported.

Again, we know that in the Java language there is a system parameter “java.class.path” that records our current classpath. However, using these two functions actually changes the actual classpath. It doesn’t have any effect on the property itself.

# # information

Java Attach API JavaAgent source code analysis JavaAgent

Pay attention and don’t get lost

The article continues to update every week, you can wechat search “ten minutes to learn programming” the first time to read and urge more, if this article is written well, feel something ~ for praise 👍 for attention ❤️ for share ❤️ everyone’s support and recognition, is the biggest power of my creation, we see the next article!