Java Instrumentation (reference: http://www.ibm.com/developerworks/cn/java/j-lo-jse61/)
Brief introduction:
With instrumentation, developers can build application-independent agents to detect and assist programs running on the JVM, and even to replace and modify the definitions of certain classes
Problems encountered:
Applications running in the Tomcat container, because the main method is executed when the container is started in the Bootstrap.jar,
The Agent-class method obtains only some of the classes in the Tomcat-related jar package in the replacement methods:
is printed in the transform method, this method will be introduced in the second
Specific Description:
The following are two ways of Premain and Agentmain, respectively, before and after the main function is executed
One: Premain
The main function executes, scans the specific class, and then loads the byte-code file of the proxy class in a byte array, replacing the target class:
Example code:
Public class Transclass { publicint getnumber () { return 2; }}
Transclass
ImportJava.io.File;ImportJava.io.FileInputStream;Importjava.io.IOException;ImportJava.io.InputStream;ImportJava.lang.instrument.ClassFileTransformer;Importjava.lang.instrument.IllegalClassFormatException;ImportJava.security.ProtectionDomain;classTransformerImplementsClassfiletransformer { Public Static FinalString classNumberReturns2 = "D://aop//transclass.class.2"; Public Static byte[] Getbytesfromfile (String fileName) {Try { //PreconditionFile File =NewFile (fileName); InputStream is=Newfileinputstream (file); LongLength =file.length (); byte[] bytes =New byte[(int) length]; //Read in the bytes intOffset = 0; intNumread = 0; while(Offset <bytes.length && (numread = is.read (bytes, offset, bytes.length-offset)) >= 0) {offset+=Numread; } if(Offset <bytes.length) {Throw NewIOException ("Could not completely read file" +file.getname ()); } is.close (); returnbytes; } Catch(Exception e) {System.out.println ("Error occurs in _classtransformer!" +E.getclass (). GetName ()); return NULL; } } Public byte[] Transform (ClassLoader L, String ClassName, class<?>C, Protectiondomain PD,byte[] b)throwsillegalclassformatexception {if(!classname.equals ("Transclass")) { return NULL; } returnGetbytesfromfile (CLASSNUMBERRETURNS2); }}
Transformer
Public class Testmaininjar { publicstaticvoid main (string[] args) { System.out.println (new transclass (). GetNumber ());} }
Testmaininjar
Import java.lang.instrument.UnmodifiableClassException; Import java.lang.instrument.Instrumentation; Public class Premain {publicstaticvoid premain (String Agentargs, Instrumentation Inst) throws ClassNotFoundException, unmodifiableclassexception { inst.addtransformer (new Transformer ());
Premain
Manifest-version:1.0premain-class:premain
MANIFEST. MF
Steps:
1. Change the Transclass.java to return 2; The compiled Transclass.class is renamed Transclass.class.2 to prevent the same name as the original Transclass.class
2. Package: jar-cvf0 testinstrument1.jar transclass.class transformer.class testmaininjar.class Premain.class
Replace the MANIFEST.MF file after hitting the jar, (no way to get this file directly into the jar package).
3. Command line execution
1) JAVA-JAVAAGENT:TESTINSTRUMENT1.JAR-CP Testinstrument1.jar Testmaininjar
2) JAVA-CP Testinstrument1.jar Testmaininjar
(Transclass.class.2 and Testinstrument1.jar need to be placed in the D:\AOP directory)
When executed with the first command, the contents of the transclass.class.2 are loaded in to replace the Transclass.class in the jar package, and the second command executes the Transclass.class in the jar package normally.
Two: Agent-class
Import java.lang.instrument.Instrumentation; Public class loadedagent { @SuppressWarnings ("Rawtypes") publicstaticvoid Agentmain (String args, Instrumentation inst) { = inst.getallloadedclasses (); // Inst.addtransformer (New Transformer ()); for (Class cls:classes) { System.out.println (Cls.getname ()); }}}
loadedagent
Public class TARGETVM { publicstaticvoidthrows interruptedexception{ while (true) { thread.sleep (+); }}}
TARGETVM
Importjava.io.IOException;Importcom.sun.tools.attach.AgentInitializationException;Importcom.sun.tools.attach.AgentLoadException;Importcom.sun.tools.attach.AttachNotSupportedException;ImportCom.sun.tools.attach.VirtualMachine; Public classTest { Public Static voidMain (string[] args)throwsattachnotsupportedexception, IOException, Agentloadexception, agentinitializationexception {Virtua Lmachine VMS= Virtualmachine.attach ("1244"); Vm.loadagent ("D:/aop/agentmain/agentaop.jar"); }}
Test
1.0 Agent-class:loadedagent
MANIFEST. MF
Steps:
1. Loadedagent.class and MANIFEST.MF into the jar package
2. Execute Targetvm.class get process number PID
3. Perform Test.class pid as a parameter
Attention:
1. Compile with Tools.jar Javac-cp Tools.jar in the Lib directory of the JDK Test.java
2. Execute command (1244 is process number): Java-classpath "D:/aop/agentmain/tools.jar" Test 1244