Additional annotations to Java Agent Technology

Posted by sqishy on Sun, 01 Sep 2019 05:31:20 +0200

What is Java Agent (Java Probe)? You can understand it as the Java version of AOP. Just run this AOP project once at startup

Java Agent runs only once at project startup and only after the java file is compiled into a class file. So it won't affect the class file.
Java Agent is a parasitic project. That is, you need to rely on a normal project to run.

I'll show you how to use IDE as IDEA and project as maven common project structure to help us create a Java Agent project.
  1. Hold down the CTRL+SHIFT+ALT+S key and enter the Project Structure interface
  2. Choose to add JAR
  3. Select the project. Note that the link below is under SRC.
  4. Create a good directory structure, in which Premain-Class was added later. The premain method specified here is in the Agent class that follows. It's also the Java Agent startup method, and the value in Class-path is also the package we added in maven. You shouldn't have.
  5. Writing a Java Agent Method
package com.annie;

import java.lang.instrument.Instrumentation;

public class Agent {

    // Method invoked at Java Agent startup
    public static void premain(String args, Instrumentation instrumentation) {
        System.out.println("The parameters passed in are: " + args);
        System.out.println("JavaAgent Start up...");
    }

}

At this point, the Java Agent project is basically started and completed. We're creating a common project (project type doesn't matter)

Here I created a SpringBook project because it was a good demonstration.
  1. The Java Agent will be compiled into the jar package first, and the compiled jar package will be under the out in the project's peer directory.
  2. Set the startup configuration, and the next Hello is the passed parameter. Not essential. Don't forget to remove the = sign from time to time.
-javaagent:C:\Users\13100\Documents\IdeaProjects\BaseJava\out\artifacts\JavaAgent_jar\JavaAgent.jar=Hello
  1. Save Run

So far, a Java Agent project has been basically built successfully. Of course, we can't be satisfied with that. Here I'm going to show you the basic dynamic annotations that are not related to JaveAgent.

  1. Add the javassist package.
  <!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
    <dependency>
      <groupId>org.javassist</groupId>
      <artifactId>javassist</artifactId>
      <version>3.25.0-GA</version>
    </dependency>
  1. Write code (don't forget to recompile after writing)
package com.annie;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.AttributeInfo;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.List;

public class Agent {

    // Method invoked at Java Agent startup
    public static void premain(String args, Instrumentation instrumentation) {
        System.out.println("The parameters passed in are: " + args);
        System.out.println("JavaAgent Start up...");

        // instrumentation contains all the classes in the project. Each time the. class file is loaded, it runs once
        instrumentation.addTransformer(new ClassFileTransformer() {
            @Override
            public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

                // Here I just catch myself writing the TestController class
                if(className.equals("com/annie/controller/TestController")){
                    // Next is the use of javassist, which I'll sketch out. No details.
                    // Get a class pool.
                    ClassPool classPool = ClassPool.getDefault();

                    try {
                        // Create a new class class class. Classfile Buffer is the bytecode of the current class
                        CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
                        ClassFile classFile = ctClass.getClassFile();
                        ConstPool constPool = classFile.getConstPool();

                        // Get the annotations in the original class from here and recommend DEBUG to look at the data in attributes
                        List<AttributeInfo> attributes = classFile.getAttributes();
                        AnnotationsAttribute attributeInfo = (AnnotationsAttribute) attributes.get(1);
                        // The import package is the package of javassist
                        // Add new annotations
                        Annotation annotation = new Annotation("org.springframework.web.bind.annotation.RequestMapping", constPool);
                        attributeInfo.addAnnotation(annotation);

                        // Returns a new bytecode
                        return ctClass.toBytecode();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return new byte[0];
            }
        });
    }
}

  1. Write a TestController, and here I just give RestController a comment. RequestMapping is not commented. Request Mapping was added to me by Java Agent.
package com.annie.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.lang.annotation.Annotation;
@RestController
public class TestController {
    @RequestMapping("/test")
    public String test() {
        // Use reflection to view Class annotations.
        Class<? extends TestController> aClass = this.getClass();
        Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();
        StringBuffer sb = new StringBuffer();
        // View all annotations on the class
        for (Annotation annotation : declaredAnnotations) {
            sb.append(annotation.toString() + "\n");
        }
        return sb.toString();
    }
}
  1. Enter 127.0.0.1:8080/test on the browser to view comments on TestController

Supplementary linux Publishing Projects

Put javaAgent.jar and javaassist.jar into a folder.

Running commands

java -javaagent:JavaAgent.jar -jar web-test-0.0.1-SNAPSHOT.jar

The project started successfully. Note that this jar package is your bulid JAR

Extended content
github
Personal Blog

Topics: Java Maven Linux snapshot