正 文

使用 Java 平台管理 bean


www.7dspace.com  更新日期:2006-5-5 6:04:45  七度空间


使用 MXBean

java.lang.management 文档中列出了每个 MXBean 接口定义的操作。通过这些操作,用户可以管理和监视虚拟机。例如,MemoryMXBean 上的操作允许打开内存系统的详细输出、请求垃圾收集以及检索当前堆和非堆内存池使用的内存的详细信息。所以,如果关心 Java 应用程序所使用的内存数量或者希望调整堆的尺寸,可以容易地用 java.lang.management API 编写管理客户机,连接到应用程序并监视内存的使用情况。

类似地,ThreadMXBean 也提供了 Java 应用程序挂起时会有用的功能。findMonitorDeadlockedThreads() 方法返回被它标识为死锁的线程的 ID。然后就可以用这些 ID 来检索线程的详细信息,包括它们的堆栈跟踪、它们的状态、它们是否在执行本机代码,等等。

这个线程信息是在 ThreadInfo 类的实例中提供的,这个类是 java.lang management 包中提供的由 MXBean 用来向用户返回数据快照的三个类的中一个 —— 其他两个是 MemoryUsage 和 MemoryNotificationInfo 类。这三个类中的每个类都是一个复杂的 数据类型,包含用于描述特定平台性质的结构化信息。

现在来看两个示例场景,演示一下上面讨论的概念如何转变成 Java 代码。

示例 1:通过 MXBean 或代理监视虚拟机

正如前面讨论过的,MXBean 的方法既可以直接在本地 MXBean 上调用,也可以通过代理调用。清单 8 展示了如何使用 ThreadMXBean 的 getter 和 setter 操作。这个示例中的 threadBean 变量既可以是从本机虚拟机检索的 MXBean,也可以是从远程虚拟机检索的 MXBean 的代理。一旦得到了引用,那么对于调用者来说就是透明的。

清单 8. 获取和设置 ThreadMXBean 的值

try {
    // Get the current thread count for the JVM
    int threadCount = threadBean.getThreadCount();
    System.out.println(" Thread Count = " + threadCount);
       
    // enable the thread CPU time
    threadBean.setThreadCpuTimeEnabled(true);
} catch ...

清单 8 中使用的 setThreadCpuTimeEnabled() 方法在 5.0 兼容的虚拟机中是可选支持的。在使用清单 9 所示的可选功能时,需要进行检查:

清单 9. 在尝试使用可选属性之前,检查是否支持可选属性

if (threadBean.isThreadCpuTimeSupported()) {
    threadBean.setThreadCpuTimeEnabled(true);
}

CompilationMXBean 类型的 getTotalCompilationTime() 方法也包含不必在每个 5.0 兼容虚拟机实现中都必须有的功能。就像清单 9 中的 setThreadCpuTimeEnabled() 一样,也有相关的方法用来检查支持是否存在。不利用这些检测方法的代码需要处理可选方法可能抛出的任何 java.lang.UnsupportedOperationException。

清单 10 展示了如何访问虚拟机中运行的所有线程的信息。每个线程的信息都保存在独立的专用 ThreadInfo 对象中,随后可以查询这个对象。

清单 10. 获得虚拟机中运行的所有线程的名称

try {
    // Get the ids of all the existing threads
    long[] threadIDs = threadBean.getAllThreadIds();
    
    // Get the ThreadInfo object for each threadID
    ThreadInfo[] threadDataset = threadBean.getThreadInfo(threadIDs);
    for (ThreadInfo threadData : threadDataset) {
        if (threadData != null) {
            System.out.println(threadData.getThreadName());
        }
    }
} catch ...

记住,像 ThreadInfo、MemoryUsage 和 MemoryNotificationInfo 这样的复杂类型中包含的信息,仅仅是请求调用执行的时刻的系统快照。这些对象在您得到对它们的引用之后,不会动态更新。所以,如果应用程序需要刷新 被管理的虚拟机上这些方面的数据,需要再做另一个调用,得到更新的 ThreadInfo 或 MemoryUsage 对象。MemoryNotificationInfo 对象在这方面略有不同,因为它们不是由管理应用程序拉动的,而是在事件通知中推动的(这点 将很快详细进行讨论)。

示例 2:通过平台服务器监视远程虚拟机

用 MBeanServerConnection 访问远程 JVM 的 ThreadMXBean 不像清单 1 中的示例那样直接。首先,需要 ThreadMXBean 的一个 javax.management.ObjectName 实例。可以用与 MXBean 代理对象相同的名称创建这个实例,如清单 11 所示:

清单 11. 构建 ThreadMXBean 的 ObjectName

try {
    ObjectName srvThrdName = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME);
    ...
} catch ...

可以用 ObjectName 实例来标识特定的远程 ThreadMXBean,以调用 MBeanServerConnection 的 getAttribute()、setAttribute() 和 invoke(),如清单 12 所示:

清单 12. 将 ObjectName 用于对远程 MBean 服务器的调用

try {
    // Get the current thread count for the JVM
    int threadCount =
      ((Integer)mbs.getAttribute( srvThrdName, "ThreadCount"))。intValue();
    System.out.println(" Thread Count = " + threadCount);
    
    boolean supported =
      ((Boolean)mbs.getAttribute(srvThrdName, "ThreadCpuTimeSupported"))。booleanValue();
    if (supported) {
        mbs.setAttribute(srvThrdName,
          new Attribute("ThreadCpuTimeEnabled", Boolean.TRUE));
        ...   
    }
} catch ...

清单 13 展示了通过 MBean 服务器连接来访问虚拟机中所有当前线程的信息。使用这种方法访问的 MXBean 返回复杂的数据类型,这些复杂数据类型包装在 JMX 开放类型 —— 例如 javax.management.openmbean.CompositeData 对象中。

为什么要把复杂数据包装在中间类型中呢?记住,MXBean 可能潜在地由实际上不是用 Java 语言编写的远程应用程序来管理,也有可能由这样的 Java 应用程序来管理,它们不能访问所有用于描述托管资源的不同性质的复杂类型。虽然可以安全地假定到平台 JMX 代理的连接的两端都能理解简单类型(例如 boolean、long 和 string),还可以把它们映射到各自的实现语言中的对应类型,但是要假定每个可能的管理应用程序都能正确地解释 ThreadInfo 或 MemoryUsage 这样的复杂类型,那是不现实的。像 CompositeData 这样的开放类型可以用更基本的类型来代表复杂的(即非基本的或结构化的)数据。

如果 5.0 MXBean 的远程调用要求传递复杂类型的实例,那么对象就被转换成等价的 CompositeData。虽然这可以让信息发送到尽可能广泛的客户,却也有不足之处:实际上能够解析 ThreadInfo 和 MemoryUsage 类型的接收方 Java 应用程序仍然需要从开放类型转换到复杂类型。但即便这样,也不算是太麻烦的步骤,因为 java.lang.management 中定义的所有支持的复杂数据类型,都有静态的方便方法做这件事。

在清单 13 中,threadDataset 属性包含一组 CompositeData 对象,这些对象直接映射到 ThreadInfo 对象。对于每个线程,ThreadInfo 的静态方法 from() 被用来从 CompositeData 构建等价的 ThreadInfo 对象。可以用这个对象访问每个线程的信息。

清单 13. CompositeData 类型在网络上传输复杂数据结构

try {
    // Get the ids of all the existing threads
    long[] threadIDs = (long[])mbs.getAttribute(srvThrdName, "AllThreadIds");
    
    // Get the ThreadInfo object for each threadID. To do this we need to
    // invoke the getThreadInfo method on the remote thread bean. To do
    // that we need to pass the name of the method to run together with the
    // argument and the argument type. It's pretty ugly we know. 
    CompositeData[] threadDataset =
      (CompositeData[]) (mbs.invoke(srvThrdName, "getThreadInfo",
        new Object[]{threadIDs}, new String[] {"[J"}));
         
    // Recover the ThreadInfo object from each received CompositeData using
    // the static helper from() method and then use it to print out the
    // thread name.    
    for (CompositeData threadCD : threadDataset) {
        ThreadInfo threadData = ThreadInfo.from(threadCD);
        if (threadData != null) {
            System.out.println(threadData.getThreadName());
        }
    }
} catch ...

5页,页码:[1] [2] [3] [4] [5] 

上一篇:WindowsXP系统宽带应用技巧
下一篇:使用XML: XSLT 2.0和XQuery对比
使用 Java 平台管理 bean 作者:May Glover Gunn, George Harley,Caroline Gough 来源:developerWorks 中国
收藏此页】【打印】【关闭
站 内 搜 索
 

热 点 导 读
特 别 推 荐