Java Attach API
catalog
1. instrucment與Attach API 2. BTrace: VM Attach的兩種方式 3. Sun JVM Attach API?
1. instrucment與Attach API
JDK5中增加了一個(gè)包java.lang.instrucment,能夠?qū)VM底層組件進(jìn)行訪問(wèn)。在JDK 5中,Instrument 要求在運(yùn)行前利用命令行參數(shù)或者系統(tǒng)參數(shù)來(lái)設(shè)置代理類(lèi),在實(shí)際的運(yùn)行之中,虛擬機(jī)在初始化之時(shí)(在絕大多數(shù)的 Java 類(lèi)庫(kù)被載入之前),instrumentation的設(shè)置已經(jīng)啟動(dòng),并在虛擬機(jī)中設(shè)置了回調(diào)函數(shù),檢測(cè)特定類(lèi)的加載情況,并完成實(shí)際工作
?在Java5中,開(kāi)發(fā)基于Instrucment的應(yīng)用,需要以下幾個(gè)步驟
但是在實(shí)際的很多的情況下,我們沒(méi)有辦法在虛擬機(jī)啟動(dòng)之時(shí)就為其設(shè)定代理,這樣實(shí)際上限制了instrument的應(yīng)用。而Java SE 6的新特性改變了這種情況,通過(guò)Java Tool API中的attach方式,我們可以很方便地在運(yùn)行過(guò)程中動(dòng)態(tài)地設(shè)置加載代理類(lèi),以達(dá)到instrumentation的目的
?在JDK6中,針對(duì)這點(diǎn)做了改進(jìn),開(kāi)發(fā)者可以在main開(kāi)始執(zhí)行以后,再開(kāi)啟自己的Instrucment程序
Attach API不是Java的標(biāo)準(zhǔn)API,而是Sun公司提供的一套擴(kuò)展API,用來(lái)向目標(biāo)JVM"附著"(Attach)代理工具程序的。有了它,開(kāi)發(fā)者可以方便的監(jiān)控一個(gè)JVM,運(yùn)行一個(gè)外加的代理程序,Sun JVM Attach API功能上非常簡(jiǎn)單,僅提供了如下幾個(gè)功能
Relevant Link:
http://iamzhongyong.iteye.com/blog/1843558?
2. BTrace: VM Attach的兩種方式
BTrace的特點(diǎn)之一就是可以動(dòng)態(tài)Attach到一個(gè)運(yùn)行的JVM進(jìn)程上,然后根據(jù)BTrace腳本來(lái)對(duì)目標(biāo)JVM進(jìn)行相應(yīng)的操作
JVM的 Attach有兩種方式
0x1: 指定javaagent參數(shù)
這種方式的特點(diǎn)就是在目標(biāo)JVM啟動(dòng)時(shí),就確定好了要加載什么樣的代理對(duì)象,例如
java -javaagent:xxxx.jar TestMainTestMain.java
package test;public class TestMain { public static void main(String[] args) throws InterruptedException{System.out.println("Hello");}}TestAgent.java
package test;import java.lang.instrument.Instrumentation; import java.io.*;public class TestMain { public static void agentmain(String args, Instrumentation inst) throws Exception {System.out.println("Args:" + args);}public static void premain(String args, Instrumentation inst) throws Exception {System.out.println("Pre Args:" + args);Class[] classes = inst.getAllLoadedClasses();for (Class clazz : classes) {System.out.println(clazz.getName());}} }TestAgent類(lèi)比較簡(jiǎn)單,最終它會(huì)在目標(biāo)類(lèi)的Main方法執(zhí)行之前,執(zhí)行premain方法,其主要?jiǎng)幼魇菍⒁约凹虞d的類(lèi)打印出來(lái)。 我們需要將這個(gè)類(lèi)打包成jar文件,以便在目標(biāo)JVM啟動(dòng)時(shí)候,以參數(shù)形式指定給它。打成jar的同時(shí),設(shè)定MANIFEST.MF文件的內(nèi)容。告知目標(biāo)JVM該如何處理
Agent-Class: TestAgent Premain-Class: TestAgent Can-Redine-Classes: true Can-Retransform-Classes: true用jar命令將TestAgent打包
1. 編譯TestAgent javac TestAgent.java2. jar打包 jar cvmf MANIFEST.MF xxx.jar TestAgent.class啟動(dòng)TestMain,并設(shè)置javaagent參數(shù)
1. 編譯TestMain javac TestMain.java 2. 啟動(dòng)TestMain java -javaagent:xxx.jar TestMain0x2: 動(dòng)態(tài)Attach,load指定Agent
這種方式與之前指定參數(shù)的不同在于,其可以在JVM已經(jīng)運(yùn)行的情況下,動(dòng)態(tài)的附著上去,并可以動(dòng)態(tài)加載agent
TestMain.java
TestAgent.java
import java.lang.instrument.Instrumentation; import java.io.*;public class TestAgent { public static void agentmain(String args, Instrumentation inst) throws Exception {System.out.println("Args:" + args);}public static void premain(String args, Instrumentation inst) throws Exception {System.out.println("Pre Args:" + args);Class[] classes = inst.getAllLoadedClasses();for (Class clazz : classes) {System.out.println(clazz.getName());}} }動(dòng)態(tài)加載agent的情況下,被調(diào)用的是agentmain方法, 其會(huì)在JVMload的時(shí)候,被調(diào)用
MANIFEST.MF
將類(lèi)打包為jar包
1. 編譯TestAgent javac TestAgent.java2. jar打包 jar cvmf MANIFEST.MF xxx.jar TestAgent.class動(dòng)態(tài)附著到對(duì)應(yīng)的JVM需要使用到JDK的Attach API
Main.java
一旦運(yùn)行這個(gè)Main方法, 其就會(huì)動(dòng)態(tài)的附著到我們對(duì)應(yīng)的JVM進(jìn)程中,并為目標(biāo)JVM加載我們指定的Agent,以達(dá)到我們想做的事情, 比如BTrace就為在附著到目標(biāo)JVM后,開(kāi)啟一個(gè)ServerSocket,以便達(dá)到與目標(biāo)進(jìn)程通訊的目的
Relevant Link:
http://ivanzhangwb.github.io/btrace-vm-attach-api/?
3. Sun JVM Attach API
Sun JVM Attach API是Sun JVM中的一套非標(biāo)準(zhǔn)的可以連接到JVM上的API,從JDK6開(kāi)始引入,除了Solaris平臺(tái)的Sun JVM支持遠(yuǎn)程的Attach,在其他平臺(tái)都只允許Attach到本地的JVM上
0x1: 列出當(dāng)前所有的JVM實(shí)例描述
package test; import java.util.List;import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor;public class Test {public static void main(String[] args) {List<VirtualMachineDescriptor> list = VirtualMachine.list(); for (VirtualMachineDescriptor vmd : list) { System.out.println("pid:" + vmd.id() + ":" + vmd.displayName()); } }} //tools.jar needs to be added to the IDE's library path and the program's classpath. The tools.jar file is found in the JDK's lib directory.0x2: Attach到特定進(jìn)程的JVM上,并加載Agent
//Attach到JVM上 VirtualMachine virtualmachine = VirtualMachine.attach(pid); //加載Agent String javaHome = virtualmachine.getSystemProperties().getProperty("java.home"); String agentPath = javaHome + File.separator + "jre" + File.separator + "lib" + File.separator + "management-agent.jar"); File file = new File(agentPath); if(!file.exists()) { agentPath = javaHome + File.separator + "lib" + File.separator + "management-agent.jar"; file = new File(agentPath); if(!file.exists()) throw new IOException("Management agent not found"); } } agentPath = file.getCanonicalPath(); try { virtualmachine.loadAgent(agentPath, "com.sun.management.jmxremote"); } catch(AgentLoadException e) { throw new IOException(e); } catch(AgentInitializationException agentinitializationexception) { throw new IOException(e); } Properties properties = virtualmachine.getAgentProperties(); address = (String)properties.get("com.sun.management.jmxremote.localConnectorAddress"); virtualmachine.detach();0x3: Attach API底層實(shí)現(xiàn)(windows)
\openjdk\jdk\src\windows\classes\sun\tools\attach\WindowsAttachProvider.java
public VirtualMachine attachVirtualMachine(String vmid) throws AttachNotSupportedException, IOException {checkAttachPermission();// AttachNotSupportedException will be thrown if the target VM can be determined// to be not attachable. testAttachable(vmid);return new WindowsVirtualMachine(this, vmid); }\openjdk\jdk\src\windows\classes\sun\tools\attach\WindowsVirtualMachine.java
WindowsVirtualMachine(AttachProvider provider, String id) throws AttachNotSupportedException, IOException {//繼承HotSpotVirtualMachine super(provider, id);int pid;try {pid = Integer.parseInt(id);} catch (NumberFormatException x) {throw new AttachNotSupportedException("Invalid process identifier");}//先連接上目標(biāo)JVMhProcess = openProcess(pid);// The target VM might be a pre-6.0 VM so we enqueue a "null" command// which minimally tests that the enqueue function exists in the target// VM.try {enqueue(hProcess, stub, null, null);} catch (IOException x) {throw new AttachNotSupportedException(x.getMessage());} }WindowsVirtualMachine繼承HotSpotVirtualMachine,先看看HotSpotVirtualMachine的loadAgent方法
\openjdk\jdk\src\share\classes\sun\tools\attach\HotSpotVirtualMachine.java
loadAgentLibrary("instrument", args);
/* * Load agent library * If isAbsolute is true then the agent library is the absolute path * to the library and thus will not be expanded in the target VM. * if isAbsolute is false then the agent library is just a library * name and it will be expended in the target VM. */ private void loadAgentLibrary(String agentLibrary, boolean isAbsolute, String options) throws AgentLoadException, AgentInitializationException, IOException {InputStream in = execute("load",agentLibrary,isAbsolute ? "true" : "false",options);try {int result = readInt(in);if (result != 0) {throw new AgentInitializationException("Agent_OnAttach failed", result);}} finally {in.close();} }可以看到,Java在Attach到目標(biāo)進(jìn)行后,調(diào)用execute讓目標(biāo)進(jìn)行加載Agent類(lèi),我們繼續(xù)分析execute的實(shí)現(xiàn)方式,可以看到,JVM進(jìn)程間通信是JVM Attach API的核心,JVM自身就預(yù)留了執(zhí)行來(lái)自Attach進(jìn)程的指令接口
\openjdk\jdk\src\windows\classes\sun\tools\attach\WindowsVirtualMachine.java
JVM的execute方法中調(diào)用了大量native方法,并且從代碼中可以看出,JVM Attach的進(jìn)程間通信使用了管道進(jìn)行通信
Relevant Link:
http://ayufox.iteye.com/blog/655761 http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/index.html?
Copyright (c) 2015 LittleHann All rights reserved
?
總結(jié)
以上是生活随笔為你收集整理的Java Attach API的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: spring 注解简单使用
- 下一篇: Java集成openCV实现图片背景切换