Introducción al Agente Java y ejecución que requiere mucho tiempo mediante el método de supervisión Byte Buddy

1. ¿Qué es el Agente Java?

El Agente Java proporciona una forma de modificar el código de bytes cuando se carga. Hay dos formas de ejecutar: una es implementar a través de premain antes de que se ejecute el método principal; la otra es implementar a través de adjuntar api mientras el programa se está ejecutando

1) 、 Instrumentación

La instrumentación es una API proporcionada por JDK1.5 para interceptar eventos de carga de clases y modificar el código de bytes. Sus métodos principales son los siguientes:

public interface Instrumentation {
    
    
  	
  	//注册一个转换器,类加载事件会被注册的转换器所拦截
    void
    addTransformer(ClassFileTransformer transformer, boolean canRetransform);
  	
  	//重新触发类加载
    void
    retransformClasses(Class<?>... classes) throws UnmodifiableClassException;
  	
  	//直接替换类的定义
    void
    redefineClasses(ClassDefinition... definitions)
        throws  ClassNotFoundException, UnmodifiableClassException;  

2), premain()método

premain()El método es el main()método que se ejecuta antes que el método. Cuando se ejecuta, debe empaquetar el programa del agente en un paquete jar y agregar un comando para ejecutarlo al inicio:

-javaagent:<jarpath>[=<options>]

premain()Se proporcionan los dos métodos de sobrecarga siguientes. Cuando se inicia la JVM, se intentará primero el primer método y, si no, se utilizará el segundo.

    public static void premain(String agentArgs, Instrumentation inst)

    public static void premain(String agentArgs)

2. Ejecución que requiere mucho tiempo mediante el método de supervisión Byte Buddy

Byte Buddy es una biblioteca de generación y manipulación de código que se utiliza para crear y modificar clases de Java cuando se ejecuta una aplicación Java sin la ayuda de un compilador. Además de las utilidades de generación de código incluidas con la biblioteca de clases de Java, Byte Buddy también permite la creación de clases arbitrarias y no se limita a implementar interfaces para crear proxies en tiempo de ejecución. Además, Byte Buddy proporciona una API conveniente que puede usar un proxy Java o cambiar manualmente la clase durante el proceso de compilación.

Introduzca las dependencias relacionadas con Byte Buddy en pom.xml y especifique la ruta del archivo MANIFEST.MF

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ppdai</groupId>
    <artifactId>bytebuddy-agent-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.8.20</version>
        </dependency>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy-agent</artifactId>
            <version>1.8.20</version>
        </dependency>
    </dependencies>

    <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.MF文件路径-->
                        <manifestFile>
                            src/main/resources/META-INF/MANIFEST.MF
                        </manifestFile>
                        <manifest>
                            <addClasspath>true</addClasspath>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

MethodCostTime

public class MethodCostTime {
    
    
    @RuntimeType
    public static Object intercept(@Origin Method method, @SuperCall Callable<?> callable) throws Exception {
    
    
        long start = System.currentTimeMillis();
        try {
    
    
            //原有函数执行
            return callable.call();
        } finally {
    
    
            System.out.println(method + " 方法耗时: " + (System.currentTimeMillis() - start) + "ms");
        }
    }
}

MyAgent :

public class MyAgent {
    
    
    public static void premain(String agentArgs, Instrumentation inst) {
    
    
        System.out.println("MyAgent init...");

        AgentBuilder.Transformer transformer = (builder, typeDescription, classLoader, javaModule) -> builder
                //拦截任意方法
                .method(ElementMatchers.any())
                //委托
                .intercept(MethodDelegation.to(MethodCostTime.class));

        AgentBuilder.Listener listener = new AgentBuilder.Listener() {
    
    
            @Override
            public void onDiscovery(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
    
    

            }

            @Override
            public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b, DynamicType dynamicType) {
    
    

            }

            @Override
            public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, boolean b) {
    
    

            }

            @Override
            public void onError(String s, ClassLoader classLoader, JavaModule javaModule, boolean b, Throwable throwable) {
    
    

            }

            @Override
            public void onComplete(String s, ClassLoader classLoader, JavaModule javaModule, boolean b) {
    
    

            }

        };

        new AgentBuilder
                .Default()
                //指定需要拦截的类
                .type(ElementMatchers.nameStartsWith("com.ppdai"))
                .transform(transformer)
                .with(listener)
                .installOn(inst);
    }
}

src/main/resourcesAgregue un META-INF/MANIFEST.MFarchivo en el directorio , el contenido es el siguiente:

Manifest-Version: 1.0
Premain-Class: com.ppdai.agent.MyAgent
Can-Redefine-Classes: true

Utilizar mvn clean packageembalaje

Categoría de prueba :

public class AgentTest {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread.sleep(new Random().nextInt(500));
    }
}

Debe especificar la ruta del paquete jar del agente al ejecutar la clase de prueba

-javaagent:<jarpath>[=<options>]

Resultado de la operación :

MyAgent init...
public static void com.ppdai.test.AgentTest.main(java.lang.String[]) throws java.lang.InterruptedException 方法耗时: 350ms

Referencia :

https://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650130323&idx=3&sn=f22cf468dd7a85539c5ab40cee8bb9ef

https://bugstack.blog.csdn.net/article/details/100044939

https://blog.csdn.net/generalfu/article/details/106086475

Supongo que te gusta

Origin blog.csdn.net/qq_40378034/article/details/115277963
Recomendado
Clasificación