, Hot deployment, supporters behind the Java JVM modal Java Agent

Our usually write Java Agent's really not much, it can be said almost no need. But in fact we have been using it, but also access to very much. The following techniques are used in Java Agent technology, look at you will know why.

- various Java IDE debugging functions, such as eclipse, IntelliJ;

- hot deployment, e.g. JRebel, XRebel, spring-loaded;

- variety of online diagnostic tools, such as Btrace, Greys, as well as Ali Arthas;

- a variety of performance analysis tools, such as Visual VM, JConsole and so on;

Java, called Java Agent literal translation agency, there is another call, called Java probe. First, that Java Agent is a jar package, but this jar package can not be run independently, it needs to attach to our target JVM process. Let's understand what these two is called.

Agent : Let's say we need to understand some of the performance indicators target the JVM, we can be achieved by Java Agent, so it is a proxy of the effect of view, we finally got the indicators is the target JVM, but we are to get through the Java Agent , the target for the JVM, it looks like a proxy;

Probe : this argument I feel very image, JVM once run up to the outside world, it is a black box. The Java Agent can be inserted like a needle-like internal JVM, to explore what we want, and can inject something into it.

We usually take a few above techniques will be used, for example child. Take IDEA debugger for instance, when a debugging, the debugger panel can be seen in the current structure and content of the context variable, you can run some simple code in watches panel, such as the value of the assignment and other operations. There Btrace, Arthas these online troubleshooting tool, for example there is the interface does not return results as expected, but the log and no wrong, then, as long as we know where the package name method, class names, method names, etc., do not modify deployment services can be found in the call parameters, return values, abnormal and other information.

When it comes to just above the detection function, and it is not just hot deployment capabilities to detect so simple. Hot deployment means is that in the case do not restart the services, ensure that the latest code logic into force in the service. When we modify a class, Java Agent by the instrument mechanism, replacing the previous byte code new code corresponding to the byte code.

Java Agent structure


Java Agent eventually in the form of a jar. It comprises two main parts, one implementation code, part of the configuration file.

Profiles on the META-INF directory, a file called MANIFEST.MF. Configuration includes the following items:

Manifest-Version: The version number
Created-By: creators
Agent-Class: the class where agentmain method
Can-Redefine-Classes: whether a class can be achieved redefine
Can-Retransform-Classes: if you can achieve the bytecode replace
Premain-Class: premain method where the class

Entrance class realization agentmainand premaintwo methods can, methods to achieve what function it was decided by your needs.

Implementation and use Java Agent

Then you come to realize a simple Java Agent, based on Java 1.8, the main achievement of two simple functions:

1, print the names of all classes currently loaded;

2, a particular method of monitoring, in the method of dynamic insertion code and a simple method for obtaining a return value;

In the method of inserting code is mainly used bytecode modification techniques, there are techniques to modify the bytecode Javassist, ASM, the ASM has been advanced packaging scalable CGLIB, this example is used javassist. So it is necessary to introduce relevant maven package.

<dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.12.1.GA</version>
</dependency>

And logic functions to achieve the inlet class

Inlet type said above, to achieve agentmain, and premaintwo methods. Run timing of these two methods are not the same. This from the use of Java Agent is a, Java Agent There are two ways to start, one is JVM startup parameters -javaagent:xxx.jarin the form of start together with the JVM, in this case, calls the premainmethod, and is the main process mainThe method of execution before. Another method is loadAgent the JVM dynamically attach to the target, in this case, executes agentmainthe method.

Loading Execution method
-javaagent: xxx.jar parameters form premain
Dynamic attach agent main

Code is implemented as follows:

package kite.lab.custom.agent;

import java.lang.instrument.Instrumentation;

public class MyCustomAgent {
    /**
     * jvm 参数形式启动,运行此方法
     * @param agentArgs
     * @param inst
     */
    public static void premain(String agentArgs, Instrumentation inst){
        System.out.println("premain");
        customLogic(inst);
    }

    /**
     * 动态 attach 方式启动,运行此方法
     * @param agentArgs
     * @param inst
     */
    public static void agentmain(String agentArgs, Instrumentation inst){
        System.out.println("agentmain");
        customLogic(inst);
    }

    /**
     * 打印所有已加载的类名称
     * 修改字节码
     * @param inst
     */
    private static void customLogic(Instrumentation inst){
        inst.addTransformer(new MyTransformer(), true);
        Class[] classes = inst.getAllLoadedClasses();
        for(Class cls :classes){
            System.out.println(cls.getName());
        }
    }
}

We see these two methods have parameters agentArgs and inst, which is a parameter agentArgs brought in when we start the Java Agent, for example -javaagent:xxx.jar agentArgs. Instrumentation Java open up specifically for the realization of bytecode modification and monitoring of the program. Print we want to achieve the loaded class and modify the byte code that is based on it to achieve. In which inst.getAllLoadedClasses()a method is realized so get loaded class features.

inst.addTransformerThe method of the bytecode modification is the key, the latter parameter is to achieve implementation class bytecode modification, as follows:

public class MyTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        System.out.println("正在加载类:"+ className);
        if (!"kite/attachapi/Person".equals(className)){
            return classfileBuffer;
        }

        CtClass cl = null;
        try {
            ClassPool classPool = ClassPool.getDefault();
            cl = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
            CtMethod ctMethod = cl.getDeclaredMethod("test");
            System.out.println("获取方法名称:"+ ctMethod.getName());

            ctMethod.insertBefore("System.out.println(\" 动态插入的打印语句 \");");
            ctMethod.insertAfter("System.out.println($_);");

            byte[] transformed = cl.toBytecode();
            return transformed;
        }catch (Exception e){
            e.printStackTrace();

        }
        return classfileBuffer;
    }
}

Logic code above is encountered when the class is loaded kite.attachapi.Personwhen the therein testinserted a print statement method starts the print content "dynamic insertion of print statements", at testthe end of the method, to print the return value, which $_is the return value this is javassist in particular identifier.

MANIFEST.MF profile

Create a file called MANIFEST.MF file in the directory resources / META-INF /, in which the content by adding the following configuration:

Manifest-Version: 1.0
Created-By: fengzheng
Agent-Class: kite.lab.custom.agent.MyCustomAgent
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Premain-Class: kite.lab.custom.agent.MyCustomAgent

Pom configuration settings required for packing

Finally, Java Agent is in the form of jar package, the final step is to hit the top of a jar package contents.

Add the following configuration in the pom file

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

Using a maven's maven-assembly-plugin plugin, note the path where the use manifestFile specify which MANIFEST.MF, and then specify the jar-with-dependencies, the dependencies to break into.

Above this is a way of packaging, with the need for a separate MANIFEST.MF, there is a way , does not require a separate add MANIFEST.MF configuration file in the project, fully configured in pom file can be.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <goals>
                        <goal>attached</goal>
                    </goals>
                    <phase>package</phase>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                        <archive>
                            <manifestEntries>
                                <Premain-Class>kite.agent.vmargsmethod.MyAgent</Premain-Class>
                                <Agent-Class>kite.agent.vmargsmethod.MyAgent</Agent-Class>
                                <Can-Redefine-Classes>true</Can-Redefine-Classes>
                                <Can-Retransform-Classes>true</Can-Retransform-Classes>
                            </manifestEntries>
                        </archive>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

This approach is all the contents of the MANIFEST.MF writing pom configuration, when the package will automatically generate configuration information MANIFEST.MF configuration file into the bag.

Run the Package command

Next on the simple, execute a maven command.

mvn assembly:assembly

Finally break out of the jar package default is "Project name - version number -jar-with-dependencies.jar" format to generate such a target directory.

Run-packaged Java Agent

First, write a simple test project to target JVM, later will be two ways to hang the Java Agent on the test project.

package kite.attachapi;

import java.util.Scanner;

public class RunJvm {

    public static void main(String[] args){
        System.out.println("按数字键 1 调用测试方法");
        while (true) {
            Scanner reader = new Scanner(System.in);
            int number = reader.nextInt();
            if(number==1){
                Person person = new Person();
                person.test();
            }
        }
    }
}

More than just a simple main method, while a way to ensure that the thread does not exit, and when you enter the number 1, call the person.test()method.

The following is a Person class

package kite.attachapi;

public class Person {

    public String test(){
        System.out.println("执行测试方法");
        return "I'm ok";
    }
}

Run in the command line

Because the project was created in IDEA in order to save thing, I will direct the IDEA's "Run / Debug Configurations" parameter of Riga.

-javaagent:/java-agent路径/lab-custom-agent-1.0-SNAPSHOT-jar-with-dependencies.jar

Then you can run directly see the effect, you will see the name of the class is loaded. Then the input numeral key "1", will see the contents of the bytecode modification.

Run to attach dynamic way

Before this test should first test the project up and running, and to remove the previous parameters. After the run, find its process id, general use jps -lcan be.

Attach a dynamic way is required to achieve the code, codes are as follows:

public class AttachAgent {

    public static void main(String[] args) throws Exception{
        VirtualMachine vm = VirtualMachine.attach("pid(进程号)");
        vm.loadAgent("java-agent路径/lab-custom-agent-1.0-SNAPSHOT-jar-with-dependencies.jar");
    }
}

The above method of operation of main and inputs "1" in the test procedure, the results will be the same in FIG.

Found yet, here we have a simple function is not implemented and BTrace and Arthas bit like it. We intercepted a specified method, and insert the code and return to get the results In this method. If the method name becomes available configuration items, and save the results returned to a common location, such as an in-memory database, we can not be as easily detected as Arthas online issue of it. Of course, Arthas much more complex, but the principle is the same.

The realization sun.management.Agent

You usually do not know or have never used visualVM tools like JConsole, in fact, they are using the management-agent.jar the Java Agent to achieve. If we want to allow remote viewing JVM Java service information, they tend to look at these configuration parameters:

-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=192.168.1.1
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

These parameters are management-agent.jar defined.

We advance to the next management-agent.jar package, see only a MANIFEST.MF configuration files, configuration content:

Manifest-Version: 1.0
Created-By: 1.7.0_07 (Oracle Corporation)
Agent-Class: sun.management.Agent
Premain-Class: sun.management.Agent

Class can be seen as an inlet sun.management.Agent, into this class and which can be found agentmain premain, and may see their logic. At the beginning of this class, you can see in front of us open those parameters defined remote JVM monitoring need to open the service.

Do not begrudge your " recommended " Yo

Welcome attention occasionally update this series and other articles
古时的风筝 , enter the number of the public can join the exchange group

Guess you like

Origin www.cnblogs.com/fengzheng/p/11502963.html