Java教程是针对JDK 8编写的。本页面描述的示例和实践未利用后续版本中引入的改进,并且可能使用不再可用的技术。
有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息,请参阅JDK发行说明。
在此教程中,之前的课程已经向您展示了如何创建JMX技术的MBeans和MXBeans,并将它们注册到JMX代理中。然而,之前的所有示例都使用了现有的JMX客户端JConsole。本课程将演示如何创建您自己的自定义JMX客户端。
自定义JMX客户端的一个示例,Client,包含在jmx_examples.zip中。该JMX客户端与之前课程中看到的相同的MBean、MXBean和JMX代理进行交互。由于Client类的大小,它将在以下部分中分块进行检查。
要能够从JMX客户端创建到远程运行的JMX代理的连接,您需要使用javax.management.remote包中的类。
package com.example;
...
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class Client {
...
Client类将创建JMXConnector实例,为此它将需要一个JMXConnectorFactory和一个JMXServiceURL。
JMX客户端需要一个通知处理程序,用于监听和处理可能由注册在JMX代理的MBean服务器中的MBeans发送的任何通知。JMX客户端的通知处理程序是NotificationListener接口的一个实例,如下所示。
...
public static class ClientListener implements NotificationListener {
public void handleNotification(Notification notification,
Object handback) {
echo("\n收到通知:");
echo("\t类名: " + notification.getClass().getName());
echo("\t源: " + notification.getSource());
echo("\t类型: " + notification.getType());
echo("\t消息: " + notification.getMessage());
if (notification instanceof AttributeChangeNotification) {
AttributeChangeNotification acn =
(AttributeChangeNotification) notification;
echo("\t属性名称: " + acn.getAttributeName());
echo("\t属性类型: " + acn.getAttributeType());
echo("\t新值: " + acn.getNewValue());
echo("\t旧值: " + acn.getOldValue());
}
}
}
...
此通知侦听器确定接收到的任何通知的来源,并检索存储在通知中的信息。然后,根据接收到的通知类型,它会对通知信息执行不同的操作。在本例中,当侦听器接收到AttributeChangeNotification类型的通知时,它将通过调用AttributeChangeNotification的getAttributeName、getAttributeType、getNewValue和getOldValue方法获取已更改的MBean属性的名称、类型以及其旧值和新值。
稍后在代码中创建了一个新的ClientListener实例。
ClientListener listener = new ClientListener();
Client类创建一个RMI连接器客户端,该客户端配置为连接到RMI连接器服务器。在启动JMX代理Main时,将启动该服务器。这将使JMX客户端能够与JMX代理进行交互,就像它们在同一台计算机上运行一样。
...
public static void main(String[] args) throws Exception {
echo("\n创建一个RMI连接器客户端并将其连接到RMI连接器服务器");
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
...
如您所见,Client定义了一个名为url的JMXServiceURL,它表示连接器客户端期望找到连接器服务器的位置。此URL允许连接器客户端从本地主机的端口9999上运行的RMI注册表中检索到RMI连接器服务器存根jmxrmi,并连接到RMI连接器服务器。
通过标识RMI注册表,可以创建连接器客户端。连接器客户端jmxc是由JMXConnectorFactory的connect()方法创建的JMXConnector接口的实例。调用connect()方法时,传递了url参数和一个空环境映射。
建立RMI连接后,JMX客户端必须连接到远程MBean服务器,以便能够与远程JMX代理注册的各种MBean进行交互。
...
MBeanServerConnection mbsc =
jmxc.getMBeanServerConnection();
...
通过调用JMXConnector实例jmxc的getMBeanServerConnection()方法创建了一个名为mbsc的MBeanServerConnection实例。
连接器客户端现在已连接到由JMX代理创建的MBean服务器,并且可以在连接的两端完全透明地注册MBean并对其执行操作。
首先,客户端定义了一些简单的操作来获取有关代理MBean服务器中找到的MBean的信息。
...
echo("\nDomains:");
String domains[] = mbsc.getDomains();
Arrays.sort(domains);
for (String domain : domains) {
echo("\tDomain = " + domain);
}
...
echo("\nMBeanServer default domain = " + mbsc.getDefaultDomain());
echo("\nMBean count = " + mbsc.getMBeanCount());
echo("\nQuery MBeanServer MBeans:");
Set<ObjectName> names =
new TreeSet<ObjectName>(mbsc.queryNames(null, null));
for (ObjectName name : names) {
echo("\tObjectName = " + name);
}
...
客户端调用MBeanServerConnection的各种方法,以获取不同MBean所在的域,注册在MBean服务器中的MBean的数量以及它所发现的每个MBean的对象名称。
客户端通过MBean服务器连接访问MBean服务器中的Hello MBean,通过创建MBean代理。这个MBean代理是客户端本地的,并模拟远程MBean。
...
ObjectName mbeanName = new ObjectName("com.example:type=Hello");
HelloMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName,
HelloMBean.class, true);
echo("\nAdd notification listener...");
mbsc.addNotificationListener(mbeanName, listener, null, null);
echo("\nCacheSize = " + mbeanProxy.getCacheSize());
mbeanProxy.setCacheSize(150);
echo("\nWaiting for notification...");
sleep(2000);
echo("\nCacheSize = " + mbeanProxy.getCacheSize());
echo("\nInvoke sayHello() in Hello MBean...");
mbeanProxy.sayHello();
echo("\nInvoke add(2, 3) in Hello MBean...");
echo("\nadd(2, 3) = " + mbeanProxy.add(2, 3));
waitForEnterPressed();
...
MBean代理允许您通过Java接口访问MBean,从而可以在代理上进行调用,而无需编写冗长的代码来访问远程MBean。在这里通过调用javax.management.JMX类的newMBeanProxy()方法创建了Hello的MBean代理,将MBean的MBeanServerConnection、对象名称、MBean接口的类名和true传递给它,以表示代理必须作为一个NotificationBroadcaster行为。JMX客户端现在可以执行由Hello定义的操作,就像它们是本地注册的MBean的操作一样。JMX客户端还添加了一个通知侦听器,并更改了MBean的CacheSize属性,以使其发送通知。
您可以使用与创建MBean代理相同的方式创建MXBean代理。
...
ObjectName mxbeanName = new ObjectName ("com.example:type=QueueSampler");
QueueSamplerMXBean mxbeanProxy = JMX.newMXBeanProxy(mbsc,
mxbeanName, QueueSamplerMXBean.class);
QueueSample queue1 = mxbeanProxy.getQueueSample();
echo("\nQueueSample.Date = " + queue1.getDate());
echo("QueueSample.Head = " + queue1.getHead());
echo("QueueSample.Size = " + queue1.getSize());
echo("\nInvoke clearQueue() in QueueSampler MXBean...");
mxbeanProxy.clearQueue();
QueueSample queue2 = mxbeanProxy.getQueueSample();
echo("\nQueueSample.Date = " + queue2.getDate());
echo("QueueSample.Head = " + queue2.getHead());
echo("QueueSample.Size = " + queue2.getSize());
...
如上所示,要为MXBean创建代理,您只需调用JMX.newMXBeanProxy而不是newMBeanProxy。MXBean代理mxbeanProxy允许客户端调用QueueSample MXBean的操作,就像它们是本地注册的MXBean的操作一样。
一旦JMX客户端获取了所有所需的信息并在远程JMX代理的MBean服务器上执行了所有必需的操作,连接必须关闭。
jmxc.close();
通过调用JMXConnector.close方法来关闭连接。
此示例要求Java SE平台的版本为6。要使用自定义JMX客户端Client远程监视Main JMX代理,请按照以下步骤进行:
jmx_examples.zip 保存到你的 work_dir 目录中。unzip jmx_examples.zip
work_dir 目录中编译示例 Java 类。
javac com/example/*.java
Main 应用程序,指定公开 Main 进行远程管理的属性:
java -Dcom.sun.management.jmxremote.port=9999 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
com.example.Main
将生成等待某些事件发生的确认。
Client 应用程序:
java com.example.Client
显示已获取 MBeanServerConnection 的确认。
显示了在 Main 启动的 MBean 服务器中注册的所有 MBean 的域。
显示了在 MBean 服务器中注册的 MBean 的数量,以及所有这些 MBean 的对象名称。显示的 MBean 包括在 Java VM 中运行的所有标准平台 MXBean,以及由 Main 在 MBean 服务器中注册的 Hello MBean 和 QueueSampler MXBean。
通过 Client 调用了 Hello MBean 的操作,以下是操作的结果:
Client 中以侦听来自 Main 的通知。CacheSize 属性的值从 200 更改为 150。Main 的终端窗口中,显示了 CacheSize 属性更改的确认。Client 的终端窗口中,显示了来自 Main 的通知,通知 Client CacheSize 属性的更改。Hello MBean 的 sayHello 操作。Main 的终端窗口中,显示了消息 "Hello world"。Hello MBean 的 add 操作。由 Client 显示结果。通过 Client 调用了 QueueSampler MXBean 的操作,以下是操作的结果:
QueueSample 的值 date、head 和 size。clearQueue 操作。Client 关闭与 MBean 服务器的连接,并显示确认。