This is the 7th day of my participation in the August More Text Challenge

preface

In the previous section how SpringBoot projects access SkyWalking, SkyWalking access projects were introduced: Jar is changed from java-jar demo.jar to java-java-javaAgent :agent.jar -jar demo.jar. So what is the existence of Agent in the end, today’s introduction to Java Agent.

Java Agent profile

A Java agent is an interceptor that comes in front of your main method. That is, it executes the agent’s code before the main method executes.

Typically, a Java proxy is just a tailor-made JAR file. It makes use of the Instrumentation API provided by the JVM to change existing bytecode loaded into the JVM.

We usually define two methods when using an Agent:

  • Premain – Agents are statically loaded at JVM startup with the -JavaAgent parameter
  • Agentmain – Dynamically loads the agent into the JVM using the Java Attach API

To summarize: Java Agent is essentially a Jar package (which requires specific methods to be implemented) that starts differently than a normal Jar package. For normal Jar packages, the Java Agent cannot be started independently by specifying the main function of the class, but must be run attached to a Java application. Let’s take a look at how to implement a minimal demo.

The development of the Agent

Project is maven project initialized in Idea:

  • Java version 11
  • Maven version 3.6.3

The project catalog is as follows:

├ ─ ─ agent - demo. On iml ├ ─ ─ pom. The XML └ ─ ─ the SRC ├ ─ ─ the main │ ├ ─ ─ Java │ │ ├ ─ ─ AgentDemo. Java │ │ └ ─ ─ AgentMain. Java │ └ ─ ─ the resources │ ├ ─ ├ ─ imptest└ ─ ─ JavaCopy the code

The demo

This code does not have any logic, so only two lines of text output are defined to show that the program is working properly

public class AgentMain {
    public static void main(String[] args) {
        System.out.println("Agent main start");
        System.out.println("Agent main end"); }}Copy the code

Run our program after compiling, normally run our code:

java  AgentMain
Agent main start
Agent main end
Copy the code

Define the Agent

  • The custom Agent must implement the premain method
  • ClassFileTransformerYou can see the classes that the JVM loads by default
public class AgentDemo {

    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("agentArgs : " + agentArgs);
        inst.addTransformer(new DefineTransformer(),true);
    }

    static class DefineTransformer implements ClassFileTransformer {

        @Override
        public byte[] transform(ClassLoader loader, String className, Class<? > classBeingRedefined, ProtectionDomain protectionDomain,byte[] classfileBuffer) throws IllegalClassFormatException {
            System.out.println("premain load Class:" + className);
            returnclassfileBuffer; }}}Copy the code

Packaging Agent

New resource/meta-inf/MANIFEST. The MF:

Manifest-version: 1.0 implementation-version: 0.0.1 -snapshot premain-class: AgentDemo can-re-classes: trueCopy the code

Using the Maven wrapper, focus only on build-related configurations:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                    </manifest>
                    <manifestEntries>
                        <Premain-Class>AgentDemo</Premain-Class>
                        <Agent-Class>AgentDemo</Agent-Class>
                        <Can-Redefine-Classes>true</Can-Redefine-Classes>
                        <Can-Retransform-Classes>true</Can-Retransform-Classes>
                    </manifestEntries>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>
Copy the code

Builder:

mvn package
Copy the code

The test agent

Go to target/classes, the maven build product directory, and execute the startup code:

java -javaagent:.. / agent - demo - 0.0.1 - the SNAPSHOT. Jar ="Hello World" AgentMain
Copy the code

The specific implementation is as follows:

premain agentArgs : Hello World
premain load Class:sun/launcher/LauncherHelper
premain load Class:java/lang/WeakPairMap$Pair$Weak
premain load Class:java/lang/WeakPairMap$WeakRefPeer
premain load Class:java/lang/WeakPairMap$Pair$WeakThe $1
premain load Class:java/lang/StringCoding
premain load Class:sun/nio/cs/ISO_8859_1
premain load Class:sun/nio/cs/US_ASCII
premain load Class:java/lang/StringCodingThe $1
premain load Class:java/lang/ThreadLocal$ThreadLocalMap
premain load Class:java/lang/ThreadLocal$ThreadLocalMap$Entry
premain load Class:jdk/internal/misc/TerminatingThreadLocal
premain load Class:java/lang/StringCoding$Result
premain load Class:AgentMain
Agent main start
Agent main end
premain load Class:jdk/internal/misc/TerminatingThreadLocalThe $1
premain load Class:java/lang/Shutdown
premain load Class:java/lang/Shutdown$Lock
Copy the code

You can see that in addition to the normal classloading output, the output contains the normal running output of the program as well as the parameters passed in.

conclusion

You can see the introduction of agents to control programs without intruding into the code. Implements similar functionality to AOP, but is lighter and more program-friendly than AOP.

Except for the Java Agent technology used in SkyWalking above. This technique can be used in hot deployments like Java schemas. However, it is possible to use techniques such as Byte Buddy (JVM runtime code generation) in specific situations.

Refer to the article

  • Java dynamic debugging technology principle and practice