获得 MXBean
客户机代码访问 MXBean 有三种方式:通过工厂方法、通过平台服务器 或作为代理。
工厂方法
检索 MXBean 最简单的方式就是使用 java.lang.management.ManagementFactory 类提供的静态方法。但是,用这种方式得到的 MXBean 只能用来监视本地虚拟机。ManagementFactory 类为每种 MXBean 都定义了一个检索方法。有些方法返回 MXBean 的单一实例,有些方法返回 MXBean 实例的强类型 List。
在指定类型只有一个 MXBean 时,检索它的代码很简单。清单 1 展示了检索 ThreadMXBean 的代码:
清单 1. 检索平台惟一的 ThreadMXBean 的引用
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
对于可能存在多个 MXBean 实例的那些 MXBean 类型来说,存在着工厂方法,可以在 List 中返回 MXBean,如清单 2 所示:
清单 2. 检索平台上所有已知的 MemoryPoolMXBean 的强类型列表
List<MemoryPoolMXBean> memPoolBeans = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean mpb : memPoolBeans) {
System.out.println("Memory Pool: " + mpb.getName());
}
LoggingMXBean 是 java.util.logging 包的一部分,所以,要用 LogManager 类而不是 ManagementFactory 类来访问它,如清单 3 所示:
清单 3. 从 LogManager 得到 LoggingMXBean 引用
LoggingMXBean logBean = LogManager.getLoggingMXBean();
记住,这些方法只允许访问属于本地 虚拟机的 MXBean。如果想把客户机代码扩展到能够一同处理位于同一台机器或不同结点上的远程 JVM,那么需要使用下面介绍的两种方法中的一种。
通过平台服务器
组织代码,以对远程虚拟机的 MBean 服务器的连接进行调用,是一种可行的选择。要让这个选择成功,首先需要用关键的命令行选项启动远程虚拟机。这些选项设置虚拟机的相关 JMX 代理侦听请求的端口,以及起作用的安全级别。例如,以下选项启动的虚拟机,其代理会在 1234 端口上侦听,且没有安全性:
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
本文后面的 安全性 一节将介绍对虚拟机的安全访问。
有了远程代理侦听,就可以使用清单 4 中的代码段获得相关 MBean 服务器连接的引用:
清单 4. 用 JMXConnectorFactory 连接不同虚拟机的 MBean 服务器
try {
// connect to a separate VM's MBeanServer, using the JMX RMI functionality
JMXServiceURL address =
new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:1234/jmxrmi");
JMXConnector connector = JMXConnectorFactory.connect(address);
MBeanServerConnection mbs = connector.getMBeanServerConnection();
} catch ...
一旦检索到 MBeanServerConnection,就可以使用 JMX 方法 getAttribute()、setAttribute() 和 invoke() 操作 MXBean。这将在 通过平台服务器监视远程虚拟机 中介绍。
作为代理
访问平台 bean API 的第三种方法与前面介绍的两种方法有共同之处。像以前一样,需要检索到被监视虚拟机的 JMX 代理的 MBeanServerConnection。然后,通过使用 ManagementFactory 类的静态助手方法,客户机代码可以请求注册到远程虚拟机的 MBean 服务器上的一个指定 MXBean 的代理实例。清单 5 展示了一个示例:
清单 5. 到远程 MBean 服务器的引用能够获得远程 MXBean 的代理
try {
ThreadMXBean threadBean = ManagementFactory.newPlatformMXBeanProxy
(mbs, ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
} catch ...
对于所有的单体 MXBean(除了 LoggingMXBean),在 ManagementFactory 类的公共静态字段中可以得到用来进行服务器注册的完整字符串名称。例如,ThreadMXBean 的 javax.management.ObjectName 的字符串表示就保存在 THREAD_MXBEAN_NAME 字段中,而 LoggingMXBean 的注册名称则保存在 java.util.logging.LogManager 类的静态字段中。清单 6 展示了对 LoggingMXBean 代理实例的请求:
清单 6. LoggingMXBean 的字符串名称是 java.util.logging.LogManager 类的常量
try {
LoggingMXBean logBean = ManagementFactory.newPlatformMXBeanProxy
(mbs, LogManager.LOGGING_MXBEAN_NAME, LoggingMXBean.class);
} catch ...
对于可能在虚拟机中存在不止一个实例的 MXBean 类型,事情变得略微麻烦一些。在这种情况下,首先需要用 MBeanServerConnection 获得指定类型的全部已注册 MXBean 的名称。为了方便,每个单体 MXBean 的 ObjectName 的域部分保存在 ManagementFactory 中的公共静态字段中。一旦检索到这些名称,就能用每个名称构造独立的代理实例。清单 7 展示了一个示例:
清单 7. 为属于远程虚拟机的每个 MemoryManagerMXBean 创建代理
try {
// Get the names of all the Memory Manager MXBeans in the server
Set srvMemMgrNames = mbs.queryNames(new ObjectName(
ManagementFactory.MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE + ",*"), null);
// Get a MXBean Proxy for each name returned
for (Object memMgrName : srvMemMgrNames){
// Cast Object to an ObjectName
ObjectName memMgr = (ObjectName) memMgrName;
// Call newPlatformMXBeanProxy with the complete object name
// for the specific MXBean
MemoryManagerMXBean memMgrBean =
ManagementFactory.newPlatformMXBeanProxy(
mbs, memMgr.toString(), MemoryManagerMXBean.class);
// memMgrBean is a proxy to the remote MXBean. We can use it
// just as if it was a reference to a local MXBean.
System.out.println("Memory Manager Name = " +
memMgrBean.getName());
}
} catch ...
