不用重新配置,用jconsole連接遠程機器進程及獲得本地進程的JMX Url的終極辦法
估計有很多人都在想用jconsole連接遠程機器上的進程時,發現沒有配置jmx端口,或者其它的東東。
下麵介始一種很簡單的辦法,可以不用重啟遠程機器的進程:
ssh -X 192.168.66.66 -l username
連接上去之後,可以直接運行jconsole進程,然後在本機就會彈出一個jconsole的窗口了。
實際上這個不是用jconsole連接遠程機器的進程,而是把遠程機器上的X輸出轉地本地來。
如果有提示失敗,那麼可能要配置下ssh可以轉發X。
=====================================
但是如果是想用編程的方式去連接本地的Java進程,而又不能更改配置重啟。
比如你有個程序是用jmx的方式去得到監控數據的,那麼肯定不能重啟目標進程,如druid的StatViewServlet:
https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE_StatViewServlet%E9%85%8D%E7%BD%AE
可以用下麵的方法來得到本地進程的jmx url。
在以前的博客《查找本地進程的jmx url的代碼》裏有提到ActiveMQ裏獲得本地進程的jmx url的方法。
https://blog.csdn.net/hengyunabc/article/details/8938281
這個方法有時卻不起效,得到的是null,但是用jconsole卻又能連接。於是研究了下jconsole的源代碼,終於發現,原來jconsole在得不到目標進程的"com.sun.management.jmxremote.localConnectorAddress"環境變量值時,會先嚐試讓目標進程加載management-agent.jar,這樣就可以得到jmx url了。
jconsole的相關源代碼OpenJDK源代碼下麵的 jdk/src/share/classes/sun/tools/jconsole/LocalVirtualMachine.java 裏。可以在這裏直接看到:
下麵是改進後的得到本地進程jmx url的代碼,對於異常的處理不是很完善,不過不影響使用:
import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.List; import java.util.Properties; public class AbstractJmxCommand { private static final String CONNECTOR_ADDRESS = "com.sun.management.jmxremote.localConnectorAddress"; public static String getJVM() { return System.getProperty("java.vm.specification.vendor"); } public static boolean isSunJVM() { // need to check for Oracle as that is the name for Java7 onwards. return getJVM().equals("Sun Microsystems Inc.") || getJVM().startsWith("Oracle"); } public static void main(String[] args) { if (args == null || args.length == 0) { System.out.println("Usage: pid"); return; } int pid = Integer.parseInt(args[0]); System.out.println(new AbstractJmxCommand().findJMXUrlByProcessId(pid)); } /** * Finds the JMX Url for a VM by its process id * * @param pid * The process id value of the VM to search for. * * @return the JMX Url of the VM with the given pid or null if not found. */ @SuppressWarnings({ "rawtypes", "unchecked" }) protected String findJMXUrlByProcessId(int pid) { if (isSunJVM()) { try { // Classes are all dynamically loaded, since they are specific to Sun VM // if it fails for any reason default jmx url will be used // tools.jar are not always included used by default class loader, so we // will try to use custom loader that will try to load tools.jar String javaHome = System.getProperty("java.home"); String tools = javaHome + File.separator + ".." + File.separator + "lib" + File.separator + "tools.jar"; URLClassLoader loader = new URLClassLoader(new URL[]{new File(tools).toURI().toURL()}); Class virtualMachine = Class.forName("com.sun.tools.attach.VirtualMachine", true, loader); Class virtualMachineDescriptor = Class.forName("com.sun.tools.attach.VirtualMachineDescriptor", true, loader); Method getVMList = virtualMachine.getMethod("list", (Class[])null); Method attachToVM = virtualMachine.getMethod("attach", String.class); Method getAgentProperties = virtualMachine.getMethod("getAgentProperties", (Class[])null); Method getVMId = virtualMachineDescriptor.getMethod("id", (Class[])null); List allVMs = (List)getVMList.invoke(null, (Object[])null); for(Object vmInstance : allVMs) { String id = (String)getVMId.invoke(vmInstance, (Object[])null); if (id.equals(Integer.toString(pid))) { Object vm = attachToVM.invoke(null, id); Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null); String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS); if (connectorAddress != null) { return connectorAddress; } else { break; } } } //上麵的嚐試都不成功,則嚐試讓agent加載management-agent.jar Method getSystemProperties = virtualMachine.getMethod("getSystemProperties", (Class[])null); Method loadAgent = virtualMachine.getMethod("loadAgent", String.class, String.class); Method detach = virtualMachine.getMethod("detach", (Class[])null); for(Object vmInstance : allVMs) { String id = (String)getVMId.invoke(vmInstance, (Object[])null); if (id.equals(Integer.toString(pid))) { Object vm = attachToVM.invoke(null, id); Properties systemProperties = (Properties)getSystemProperties.invoke(vm, (Object[])null); String home = systemProperties.getProperty("java.home"); // Normally in ${java.home}/jre/lib/management-agent.jar but might // be in ${java.home}/lib in build environments. String agent = home + File.separator + "jre" + File.separator + "lib" + File.separator + "management-agent.jar"; File f = new File(agent); if (!f.exists()) { agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; f = new File(agent); if (!f.exists()) { throw new IOException("Management agent not found"); } } agent = f.getCanonicalPath(); loadAgent.invoke(vm, agent, "com.sun.management.jmxremote"); Properties agentProperties = (Properties)getAgentProperties.invoke(vm, (Object[])null); String connectorAddress = agentProperties.getProperty(CONNECTOR_ADDRESS); //detach 這個vm detach.invoke(vm, (Object[])null); if (connectorAddress != null) { return connectorAddress; } else { break; } } } } catch (Exception ignore) { System.err.println(ignore); } } return null; } }
最後更新:2017-04-03 14:54:32
上一篇:
Java之dead code——無用代碼
下一篇:
Java中的隨機數生成器:Random,ThreadLocalRandom,SecureRandom
怎麼樣才可以讓Form表單在加載的時候隻自動提交一次?
排序算法測試程序入口
天氣預報 增加公曆節日信息(1.確定時間2.第幾周第幾天) 和 農曆節日信息 體力活+外碼
《構建實時機器學習係統》一1.4 實時是個“萬靈丹”
雲棲大會馬雲精彩演講:投資千億創立“達摩院”
爬下20萬份菜譜,數據解讀舌尖上的中國 | 饕餮文本大宴
全球最牛程序員出自哪些學校 中國“神秘”高中排名第二
Windows下如何配置TensorFlow?這有個簡單明了的教程(支持GPU哦)
IDC:無線數字化轉型持續進行 第二季度全球企業WLAN市場強勁增長
市值登頂亞洲後,馬雲對話全球投資者:與未來相比阿裏還是個baby