Java Language Javassist Basique


Exemple

Javassist est une bibliothèque d'instrumentation de bytecode qui vous permet de modifier le code Java d'injection de bytecode qui sera converti en bytecode par Javassist et ajouté à la classe / méthode instrumentée lors de l'exécution.

Écrivons le premier transformateur qui prend réellement une classe hypothétique "com.my.to.be.instrumented.MyClass" et ajoute aux instructions de chaque méthode un appel de journal.

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
 
public class DynamicTransformer implements ClassFileTransformer {
 
    public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
        ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
 
        byte[] byteCode = classfileBuffer;
 
        // into the transformer will arrive every class loaded so we filter 
        // to match only what we need
        if (className.equals("com/my/to/be/instrumented/MyClass")) {
 
            try {
                // retrive default Javassist class pool
                ClassPool cp = ClassPool.getDefault();
                // get from the class pool our class with this qualified name
                CtClass cc = cp.get("com.my.to.be.instrumented.MyClass");
                // get all the methods of the retrieved class
                CtMethod[] methods = cc.getDeclaredMethods()
                for(CtMethod meth : methods) {
                    // The instrumentation code to be returned and injected
                    final StringBuffer buffer = new StringBuffer();
                    String name = meth.getName();
                    // just print into the buffer a log for example
                    buffer.append("System.out.println(\"Method " + name + " executed\" );");
                    meth.insertBefore(buffer.toString())
                }
                // create the byteclode of the class
                byteCode = cc.toBytecode();
                // remove the CtClass from the ClassPool
                cc.detach();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
 
        return byteCode;
    }
}

Maintenant, pour utiliser ce transformateur (afin que notre JVM appelle la méthode transform sur chaque classe au moment du chargement), nous devons ajouter cet instrument avec un agent:

import java.lang.instrument.Instrumentation;
 
public class EasyAgent {
 
    public static void premain(String agentArgs, Instrumentation inst) {
         
        // registers the transformer
        inst.addTransformer(new DynamicTransformer());
    }
}

La dernière étape pour démarrer notre première expérience avec un instrument consiste à enregistrer cette classe d'agent dans l'exécution de la machine JVM. Le moyen le plus simple est de l’enregistrer avec une option dans la commande shell:

java -javaagent:myAgent.jar MyJavaApplication

Comme nous pouvons le voir, le projet agent / transformer est ajouté en tant que fichier jar à l'exécution de toute application appelée MyJavaApplication qui est supposée contenir une classe nommée "com.my.to.be.instrumented.MyClass" pour exécuter réellement notre code injecté.