標籤:style blog http color java 使用 os io
Java Instrumentation (參考:http://www.ibm.com/developerworks/cn/java/j-lo-jse61/)
簡介:
使用Instrumentation,開發人員可以構建獨立於應用程式的代理程式,用來檢測和協助運行在JVM上的程式,甚至能夠替換和修改某些類的定義
遇到問題:
運行在tomcat容器中的應用程式,由於main方法是在Bootstrap.jar中容器啟動時執行的,
Agent-class方式在替換的方法中只擷取到tomcat相關jar包中的一些類:
中是在transform方法中列印出來的,這個方法會在二中介紹
具體介紹:
下面是兩種方式PreMain 和 agentMain,分別為main函數執行之前,和執行之後的操作
一:PreMain
main函數執行之間,掃描判斷特定的類,然後以位元組數組的方式載入代理類的位元組碼檔案,替換目標類:
範例程式碼:
public class TransClass { public int getNumber() { return 2; }}
TransClass
import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.lang.instrument.ClassFileTransformer;import java.lang.instrument.IllegalClassFormatException;import java.security.ProtectionDomain;class Transformer implements ClassFileTransformer { public static final String classNumberReturns2 = "D://AOP//TransClass.class.2"; public static byte[] getBytesFromFile(String fileName) { try { // precondition File file = new File(fileName); InputStream is = new FileInputStream(file); long length = file.length(); byte[] bytes = new byte[(int) length]; // Read in the bytes int offset = 0; int numRead = 0; while (offset <bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) { offset += numRead; } if (offset < bytes.length) { throw new IOException("Could not completely read file "+ file.getName()); } is.close(); return bytes; } 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) throws IllegalClassFormatException { if (!className.equals("TransClass")) { return null; } return getBytesFromFile(classNumberReturns2); }}
Transformer
public class TestMainInJar { public static void main(String[] args) { System.out.println(new TransClass().getNumber()); }}
TestMainInJar
import java.lang.instrument.UnmodifiableClassException;import java.lang.instrument.Instrumentation;public class Premain {public static void premain(String agentArgs, Instrumentation inst) throws ClassNotFoundException, UnmodifiableClassException { inst.addTransformer(new Transformer()); }}
Premain
Manifest-Version: 1.0Premain-Class: Premain
MANIFEST.MF
步驟:
1. TransClass.java 中 改成 return 2; 之後編譯產生的TransClass.class改名為TransClass.class.2 ,以防止跟原TransClass.class重名
2. 打包:jar -cvf0 TestInstrument1.jar TransClass.class Transformer.class TestMainInJar.class Premain.class
打好jar後替換manifest.mf檔案,(沒找到怎麼把這個檔案直接打進jar包)
3. 命令列執行
1)java -javaagent:TestInstrument1.jar -cp TestInstrument1.jar TestMainInJar
2)java -cp TestInstrument1.jar TestMainInJar
(TransClass.class.2 和 TestInstrument1.jar 需要放置到 D:\AOP 目錄下)
用第一個命令執行的時候,會把TransClass.class.2的內容載入進來替換jar包中的TransClass.class,而第二個命令是正常執行jar包中的TransClass.class
二: Agent-class
import java.lang.instrument.Instrumentation;public class LoadedAgent { @SuppressWarnings("rawtypes") public static void agentmain(String args, Instrumentation inst){ Class[] classes = inst.getAllLoadedClasses(); //inst.addTransformer(new Transformer()); for(Class cls :classes){ System.out.println(cls.getName()); } }}
LoadedAgent
public class TargetVM { public static void main(String[] args) throws InterruptedException{ while(true){ Thread.sleep(1000); } }}
TargetVM
import java.io.IOException;import com.sun.tools.attach.AgentInitializationException;import com.sun.tools.attach.AgentLoadException;import com.sun.tools.attach.AttachNotSupportedException;import com.sun.tools.attach.VirtualMachine;public class Test { public static void main(String[] args) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException { VirtualMachine vm = VirtualMachine.attach("1244"); vm.loadAgent("D:/AOP/agentmain/agentAop.jar"); }}
Test
Manifest-Version: 1.0Agent-Class: LoadedAgent
MANIFEST.MF
步驟:
1. 將LoadedAgent.class 和 Manifest.mf打進jar包
2. 執行TargetVM.class 擷取進程號PID
3. 執行Test.class pid作為參數
注意:
1. 編譯時間需要用到jdk中lib目錄下的tools.jar javac -cp tools.jar Test.java
2. 執行命令(1244 是進程號) :java -classpath "D:/AOP/agentmain/tools.jar" Test 1244