update: 2016-10-18
在jdk7之后,有一个jcmd的工具,可以来启动jmx:
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
参考:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr006.html
---
好久没写blog了,先来篇充充数。。
当想用JMX连接本地进程,而这个进程又没有配置JMX相关的参数,怎样才能连到这个进程?
下面的代码是从ActiveMQ的代码里抠出来的,可以得到本地进程的jmx url。
不过当目标进程配置了-Djava.io.tmpdir 参数时,不能正常工作,原因是JDK的bug。
参考:
http://dikar.iteye.com/blog/1415408
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6649594
所以ActiveMQ5.8在用命令行时,用 "./activemq-admin list" ,得不出结果,改用"./activemq list "就可以了。
原因是"activemq-admin"这个脚本里,配置了一个java.io.tmpdir 的参数。
给ActiveMQ提了个issue,不过貌似没人理。。
https://issues.apache.org/jira/browse/AMQ-4541
import java.io.File;
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");
}
/**
* 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;
}
}
}
} catch (Exception ignore) {
}
}
return null;
}
}