java.lang.instrument Agent Verwendung
Das Java.lang.Instrument -Paket wurde in JDK5 eingeführt. Programmierer können den Klassencode dynamisch ändern, indem sie den Bytecode der Methode ändern. Dies wird normalerweise vorverarbeitet, bevor die Hauptmethode der Klasse aufgerufen wird und von Java implementiert wird, um die Proxy -Klasse der Klasse anzugeben. Bevor die Bytecode der Klasse in die JVM geladen wird, wird die Transformationsmethode des ClassFileTransformer aufgerufen, um die Funktion der Änderung der ursprünglichen Klassenmethode und der Implementierung von AOP zu realisieren. Der Vorteil davon ist, dass es keine neue Klasse wie Dynamic Proxy oder CGGLIB -Technologie erzeugt, die AOP implementiert, und es ist nicht erforderlich, dass die ursprüngliche Klasse eine Schnittstelle hat.
(1) Agent ist ein Interceptor vor Ihrer Hauptmethode, dh der Code, der den Agenten vor der Ausführung der Hauptmethode ausführt. Der Code des Agenten wird in derselben JVM ausgeführt wie Ihre Hauptmethode, wird von demselben Systemklassenloader geladen und von derselben Sicherheitsrichtlinie und demselben Kontext verwaltet. Der Namensagent ist etwas irreführend und es ist nicht genau wie der Agent, den wir im Allgemeinen verstehen. Java Agent ist relativ einfach zu bedienen. Wie schreibe ich einen Java -Agenten? Sie müssen nur die Premain -Methode implementieren: Public Static Void Premain (String agentargs, Instrumentationsinst) Wenn die obige Definition von Prämain in JDK 6 nicht gefunden werden kann, werden Sie auch versuchen, die folgende Prämain -Definition zu rufen: Public static void Premin (String AgentArgs).
(2) Die Agentenklasse muss in ein JAR-Paket eingegeben werden, und dann muss das meta-inf/Mainifest.mf im Inneren das Attribut der Premain-Klasse enthalten. Hier ist ein Beispiel für Manifest.mf:
Manifestversion: 1.0 Premain-Klasse: MyAgent1 erstellt: 1.6.0_06
Fügen Sie dann Manifest.mf zu Ihrem JAR -Paket hinzu. Das Folgende ist die Manifest-Attribute, die für die Agent JAR-Datei Manifest: Premain-Klasse, wenn ein Proxy angegeben wird, wenn das JVM gestartet wird. Dieses Attribut gibt die Proxy-Klasse an, dh die Klasse, die die Premain-Methode enthält. Diese Eigenschaft ist erforderlich, wenn ein Proxy angegeben ist, wenn der JVM gestartet wird. Wenn die Eigenschaft nicht existiert, wird die JVM abbrechen. Hinweis: Diese Eigenschaft ist ein Klassenname, kein Dateiname oder ein Pfad. Agentenklasse Wenn die Implementierung den Mechanismus unterstützt, den Agenten in einem bestimmten Zeitpunkt nach Beginn der VM zu starten, gibt diese Eigenschaft die Agentenklasse an. Das heißt, die Klasse, die die AgentMain -Methode enthält. Diese Eigenschaft ist erforderlich und der Stellvertreter wird nicht gestartet, wenn es nicht vorhanden ist. Hinweis: Dies ist der Klassenname, nicht der Dateiname oder der Path. Der Boot-Class-Pfad legt die Pfadliste für Bootsklassen-Loadersuche fest. Pfade repräsentieren Verzeichnisse oder Bibliotheken (normalerweise als JAR- oder ZIP -Bibliotheken auf vielen Plattformen bezeichnet). Nach einem plattformspezifischen Mechanismus zum Finden einer Klasse sucht die Bootsklasse Loader nach diesen Pfaden. Suchen Sie die Pfade in der aufgeführten Reihenfolge. Die Pfade in der Liste sind durch einen oder mehrere Leerzeichen getrennt. Pfade verwenden die Pfadkomponentensyntax des hierarchischen URI. Wenn der Pfad mit einem Schrägstrich ("/") beginnt, ist er ein absoluter Weg, sonst ist er ein relativer Weg. Der relative Pfad wird auf der Grundlage des absoluten Pfades der Proxy -JAR -Datei analysiert. Ignorieren Sie Pfade mit falschem Format und nicht existierenden Pfaden. Wenn der Agent nach Beginn der VM zu einem bestimmten Zeitpunkt gestartet wird, wird der Pfad, der die JAR -Datei nicht darstellt, ignoriert. Diese Eigenschaft ist optional. Boolean (wahr oder falsch, irrelevant für obere und untere Fall). Ob die erforderlichen Klassen für diesen Proxy neu definiert werden können. Andere Werte als wahr werden als falsch angesehen. Diese Eigenschaft ist optional und der Standardwert ist falsch. Can-retransform-Klasse boolean (wahr oder falsch, für den oberen und unteren Fall irrelevant). Ob die erforderlichen Klassen für diesen Proxy konvertiert werden können. Andere Werte als wahr werden als falsch angesehen. Diese Eigenschaft ist optional und der Standardwert ist falsch. CAN-Set-Native-Methode-Prefix Boolean-Wert (wahr oder falsch, für den oberen und unteren Fall irrelevant). Ob das von diesem Stellvertreter erforderliche Präfix der nativen Methode erforderlich ist. Andere Werte als wahr werden als falsch angesehen. Diese Eigenschaft ist optional und der Standardwert ist falsch.
(3) Alle diese Agent -JAR -Pakete werden automatisch zum Klassenpfad des Programms hinzugefügt. Sie müssen sie also nicht manuell zum Klassenpfad hinzufügen. Es sei denn, Sie möchten die Reihenfolge der Klassenpfade angeben.
(4) Die Anzahl der Parameter von -javaagent in einem Java -Programm ist jedoch keine Begrenzung, sodass Sie so viele Java -Agenten hinzufügen können. Alle Java -Agenten werden in der Reihenfolge ausgeführt, die Sie definieren. Zum Beispiel:
java -javaagent: myagent1.jar -javaagent: myagent2.jar -jar myprogram.jar
Nehmen wir an, die Hauptfunktion in MyProgram.jar befindet sich im MyProgram. MyAgent1.jar, MyAgent2.jar, die Klassen, die Prämain in diesen beiden JAR -Paketen implementieren, sind MyAgent1, und die Ausführungsreihenfolge des MyAgent2 -Programms wird sein:
Myagent1.premain -> myagent2.premain -> myprogram.main
(5) Zusätzlich wird die nach der Hauptfunktion platzierte Prämain nicht ausgeführt, z. B.:
java -javaagent: myagent1.jar -jar myprogram.jar -javaagent: myagent2.jar
MyAgent2 befindet sich hinter MyProgram.jar, sodass die Prämain von MyAgent2 nicht ausgeführt wird, sodass das Ausführungsergebnis lautet:
MyAgent1.Premain -> MYPROGRAM.MAIN
(6) Jeder Java-Agent kann einen Parameter vom String-Typ erhalten, dh Agentargs in Premain. Diese Agentargs ist in der Java -Option definiert. Zum Beispiel:
java -javaagent: myagent2.jar = thisIlagentargs -jar MyProgram.jar
Der Wert von Agentargs, die von Premain in MyAgent2 erhalten wurden, lautet "ThisIsAgentargs" (ohne Doppelzitate).
(7) Instrumentierung im Parameter: Fügen Sie den durch den Parameter definierten ClassFileTransformer hinzu, um die Klassendatei zu ändern. Der benutzerdefinierte Transformator hier implementiert die Transformationsmethode, die Änderungen an der Bytecode der Klasse bietet, die tatsächlich ausgeführt werden soll, und kann sogar den Punkt der Ausführung einer anderen Klassenmethode erreichen. Zum Beispiel: Schreiben Sie Agentenklasse:
Paket org.toy; import java.lang.instrument.instrumentation; import java.lang.instrument /** * Diese Methode wird aufgerufen, bevor der Hauptmethode der Anwendung aufgerufen wird, * Wenn dieser Agent dem Java VM angegeben wird. **/ public static void Premain (String agentargs, Instrumentierung _inst) {System.out.println ("perfmonagent.premain () wurde genannt."); // Initialisieren Sie die statischen Variablen, mit denen wir Informationen verfolgen. Inst = _inst; // Richten Sie den Klasse-Datei-Transformator ein. ClassFileTransformer trans = neuer perfmonxformer (); System.out.println ("Hinzufügen einer Perfmonxformer -Instanz zum JVM."); inst.Addtransformer (trans); }}Schreiben Sie die Klasse für Klassenfilter:
Paket org.toy; import Java.lang.instrument Javassist.notfoundException; import Javassist.expr.expreditor; import Javassist Byte [] transformiert = null; System.out.println ("Transforming" + ClassName); Classpool pool = classpool.getDefault (); CTCLASS CL = NULL; try {cl = pool.makeclass (new java.io.BytearrayInputStream (classFileBuffer)); if (cl.Isersinterface () == false) {ctBehavior [] methoden = cl.getDeclaredBehaviors (); für (int i = 0; i <methods.length; i ++) {if (Methoden [i] .IsEmpty () == false) {Domethod (Methoden [i]); }} transformed = cl.tobytecode (); }} catch (Ausnahme e) {System.err.println ("Das konnte nicht instrument" + className + ", Ausnahme:" + e.getMessage ()); } endlich {if (cl! = null) {cl.detach (); }} return transformiert; } private void domethod (ctBehavior -Methode) löst keine FoundException aus, kann nicht compileException {// method.insertBefore ("Long Stime = System.Nanotime ();"); // method.insertafter ("system.out.println (/" lave "+method.getName ()+" und time:/"+(system.nanotime ()-stime));"); method.instrument (new extreditor () {public void edit (methodcall m) Ausfälle kann nicht compilexception {m.replace ("{long stime = system.nanotime (); ":/"+(System.Nanotime ()-Stime));} ");}}); }}); }}Die obigen zwei Klassen sind der Kern des Agenten. Wenn JVM beginnt, wird Perfmonagent.premain vor dem Laden der Anwendung aufgerufen. Anschließend wird ein individuelles Classfiletransforme, nämlich Perfmonxformer, in Perfmonagent.Premain instanziiert, und dann wird ein benutzerdefinierter Klassenfiletransformer in Perfmonxformer instanziiert, und dann wird die Instanz des Perfmonxformers zur Instrumentierungsinstanz hinzugefügt (von JVM übermittelt). Dies macht Perfmonxformer.transformation aufgerufen, wenn die Klasse in der Anwendung geladen ist. Sie können die geladene Klasse in dieser Methode ändern. Es ist wirklich magisch. Um den Bytecode der Klasse zu ändern, habe ich Jboss 'Javassist verwendet. Obwohl Sie es nicht so verwenden müssen, ist Jboss 'Javassist wirklich leistungsstark, sodass Sie den Bytecode der Klasse problemlos ändern können.
In der obigen Methode habe ich die Bytecode der Klasse geändert und lang Stime = System.nanotime () hinzugefügt; zum Methodeeingang jeder Klasse und system.out.println ("methodCassName.Methodname:"+(System.Nanotime ()-Stime));
Danke fürs Lesen, ich hoffe, es kann Ihnen helfen. Vielen Dank für Ihre Unterstützung für diese Seite!