在同一主机上查找 java 进程相当简单(稍后列出一些注意事项)。连接到他们的 JMX 接口也是可以实现的。至于跟踪数据库会话,您可以从概念上获取任何您想要的数据,只要它是通过可访问的 MBean 发布的。
该过程需要使用Java Attach API。这是一个简单的示例,我将列出在我的主机上运行的所有 JVM,尝试附加到它们并列出它们的堆使用情况。
首先,这是导入:
import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.util.List;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
com.sun.tools.attach类位于 JVM 的tools.jar中。这是代码:
public class AttachAPIExample {
/**
* Uses the attach API to locate all JVMs accessible on this machine.
* @param args None
*/
public static void main(String[] args) {
// Get my PID
final String MYPID = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
log("Scanning for JVMs...");
// List all the Virtual Machine Descriptors
List<VirtualMachineDescriptor> descriptors = VirtualMachine.list();
for(VirtualMachineDescriptor vmd: descriptors) {
VirtualMachine vm = null;
// Do this in a catch block in case we run into a JVM that is not the same "bit" as we are
try {
vm = vmd.provider().attachVirtualMachine(vmd.id());
String display = vmd.displayName().trim().isEmpty() ? "Unknown" : vmd.displayName();
log("JVM%sPID: %s Display: %s", vmd.id().equals(MYPID) ? " (Me) " : " ", vmd.id(), display);
String connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null);
if(connectorAddress!=null) {
log("\tConnector Found Installed at [%s]", connectorAddress);
} else {
String javaHome = vm.getSystemProperties().getProperty("java.home");
File agentJarFile = new File(javaHome + File.separator + "lib" + File.separator + "management-agent.jar");
if(agentJarFile.exists()) {
log("I think we can find this JVM's management agent here: [%s]", agentJarFile.toString());
vm.loadAgent(agentJarFile.getAbsolutePath());
connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress", null);
log("\tConnector Installed at [%s]", connectorAddress);
} else {
log("Cannot find the agent jar for JVM [%s] at [%s]", vmd.id(), javaHome);
}
}
// Now lets try and connect and read some MBean values
if(connectorAddress!=null) {
log("Attaching to JVM [%s]...", vmd.id());
JMXServiceURL jmxUrl = new JMXServiceURL(connectorAddress);
JMXConnector connector = null;
try {
connector = JMXConnectorFactory.connect(jmxUrl);
MBeanServerConnection conn = connector.getMBeanServerConnection();
MemoryUsage heap = MemoryUsage.from((CompositeData)conn.getAttribute(new ObjectName(ManagementFactory.MEMORY_MXBEAN_NAME), "HeapMemoryUsage"));
log("Heap Usage: %s", heap);
} finally {
if(connector!=null) {
try { connector.close(); } catch (Exception ex) {/* No Op */}
}
}
}
} catch (Exception ex) {
/* No Op */
} finally {
if(vm!=null) try { vm.detach(); } catch (Exception ex) {/* No Op */}
log("======================================");
}
}
}
public static void log(String fmt, Object...args) {
System.out.println(String.format(fmt, args));
}
}
这是一些示例输出:
Scanning for JVMs...
JVM PID: 27928 Display: sun.tools.jconsole.JConsole
Connector Found Installed at [service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LnJlbW90ZS5ybWkuUk1JU2VydmVySW1wbF9TdHViAAAAAAAAAAICAAB4cgAaamF2YS5ybWkuc2VydmVyLlJlbW90ZVN0dWLp/tzJi+FlGgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc3AAtVbmljYXN0UmVmMgAADDEwLjEyLjExNC4zNwAA9bhcC21U1Z9PMPLlR/0AAAFAxsF5moACAHg=]
Attaching to JVM [27928]...
Heap Usage: init = 8388608(8192K) used = 40242696(39299K) committed = 44236800(43200K) max = 5726666752(5592448K)
======================================
JVM PID: 25028 Display: org.jboss.Main -c ecseu -b 0.0.0.0
I think we can find this JVM's management agent here: [c:\java\jdk1.6.0_30\jre\lib\management-agent.jar]
Connector Installed at [service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LnJlbW90ZS5ybWkuUk1JU2VydmVySW1wbF9TdHViAAAAAAAAAAICAAB4cgAaamF2YS5ybWkuc2VydmVyLlJlbW90ZVN0dWLp/tzJi+FlGgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc4AAtVbmljYXN0UmVmMgAADVBQLVdLLU5XSEktMDEAAPjJTzYbxtjrUKazaPTEAAABQMuKX+6ABAB4]
Attaching to JVM [25028]...
Heap Usage: init = 1073741824(1048576K) used = 173876432(169801K) committed = 982581248(959552K) max = 982581248(959552K)
======================================
注意事项
- JMV 只能附加到相同位的 JVM(即 32 位到 32 位、64 位到 64 位)
- 启动附加的操作系统用户必须具有访问其他处理的操作系统授权。所以同一个用户,没问题。其他用户......你应该是root。
- 当在不同的 JVM 供应商实现中使用时,附加 api 会产生不同的结果。IE。如果是 Sun/Oracle/OpenJDK,你可能很好。如果是这些,并且您正在尝试连接到 IBM JVM(反之亦然),那么我不知道会发生什么,尽管 JRockit 在这方面似乎相当友好。
- 我不知道所有的警告。