The Attach API

相信使用java的开发者肯定经常使用java.*和javax.*的库。但这不是SUN的JDK唯一提供的工具库。有很多的工具库在tools.jar包下面,其中之一就是Attach API。通过此API的名称也可以猜出此API的作用是让程序可以attach到目标的JVM上。通过attach到目标JVM上,你可以监控到JVM的状态并且可以从中发现一些你感兴趣的问题。Attach API在com.sun.tools.attach 和 com.sun.tools.attach.spi包下面,总共由7个类构成。然后你不需要使用到com.sun.tools.attach.spi 包下的类,你需要了解的是VirtualMachine 和VirtualMachineDescriptor 类。

初识Attach API

VirtualMachine 类表示JVM的示例。你可以通过传给VirtualMachine类目标JVM的进程id参数来连接目标JVM,并且你可以加载一个agent来做额外的事情:

VirtualMachine vm = VirtualMachine.attach (processid);
String agent = ...
vm.loadAgent(agent);

另一种连接JVM的方式是通过迭代所有的JVM示例来选择你希望连接的JVM:

String name = ...
List vms = VirtualMachine.list();
for (VirtualMachineDescriptor vmd: vms) {
    if (vmd.displayName().equals(name)) {
        VirtualMachine vm = VirtualMachine.attach(vmd.id());
        String agent = ...
        vm.loadAgent(agent);
        // ...
    }
}

当需要断开连接的时候,可以调用detach方法。当你加载完agent后,你应该调用detach方法。

示例

在JDK中天然存在一个JMX代理,在management-agent.jar包下面。JMX代理可以远程在目标JVM上启动的一个JMX代理MBean服务,然后得到一个连接到此服务的MBeanServerConnection。通过这个连接你可以监控到JVM的很多行为,比如得到远程目标JVM的线程状态。下面我们通过一个简单的示例程序实现此功能。首先,我们的程序需要attach到一个目标JVM上。然后需要启动一个远程的JMX服务(如果没有启动的话)。代理类jar包management-agent.jar可以在目标JVM上的java.home系统环境下找到。一旦连接成功,我们就可以获取此连接,并通过此连接获取我们感兴趣的信息,比如线程的名字和状态

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import com.sun.tools.attach.VirtualMachine;

public class MonitorVMThread {
    public static void main(String args[]) throws Exception {
        if (args.length != 1) {
          System.err.println("Please provide process id");
          System.exit(-1);
        }
        VirtualMachine vm = VirtualMachine.attach(args[0]);
        String connectorAddr = vm.getAgentProperties().getProperty(
          "com.sun.management.jmxremote.localConnectorAddress");
        if (connectorAddr == null) {
          String agent = vm.getSystemProperties().getProperty(
            "java.home")+File.separator+"lib"+File.separator+
            "management-agent.jar";
          vm.loadAgent(agent);
          connectorAddr = vm.getAgentProperties().getProperty(
            "com.sun.management.jmxremote.localConnectorAddress");
          vm.detach();
        }
        JMXServiceURL serviceURL = new JMXServiceURL(connectorAddr);
        JMXConnector connector = JMXConnectorFactory.connect(serviceURL); 
        MBeanServerConnection mbsc = connector.getMBeanServerConnection(); 
        ObjectName objName = new ObjectName(
          ManagementFactory.THREAD_MXBEAN_NAME);
        Set mbeans = mbsc.queryNames(objName, null);
        for (ObjectName name: mbeans) {
          ThreadMXBean threadBean;
          threadBean = ManagementFactory.newPlatformMXBeanProxy(
            mbsc, name.toString(), ThreadMXBean.class);
          long threadIds[] = threadBean.getAllThreadIds();
          for (long threadId: threadIds) {
            ThreadInfo threadInfo = threadBean.getThreadInfo(threadId);
            System.out.println (threadInfo.getThreadName() + " / " +
                threadInfo.getThreadState());
          }
        }
      }
}

JMX的更多内容请看 http://www.ibm.com/developerworks/cn/java/j-lo-jse63/index.html

你可能感兴趣的:(深入了解JDK)