文档

Java™教程
隐藏目录
创建自定义的JMX客户端
指南:Java管理扩展(JMX)
课程:远程管理

创建自定义JMX客户端

在此教程中,之前的课程已经向您展示了如何创建JMX技术的MBeans和MXBeans,并将它们注册到JMX代理中。然而,之前的所有示例都使用了现有的JMX客户端JConsole。本课程将演示如何创建您自己的自定义JMX客户端。

自定义JMX客户端的一个示例,Client,包含在jmx_examples.zip中。该JMX客户端与之前课程中看到的相同的MBean、MXBean和JMX代理进行交互。由于Client类的大小,它将在以下部分中分块进行检查。

导入JMX远程API类

要能够从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类型的通知时,它将通过调用AttributeChangeNotificationgetAttributeNamegetAttributeTypegetNewValuegetOldValue方法获取已更改的MBean属性的名称、类型以及其旧值和新值。

稍后在代码中创建了一个新的ClientListener实例。

 
ClientListener listener = new ClientListener();

创建RMI连接器客户端

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定义了一个名为urlJMXServiceURL,它表示连接器客户端期望找到连接器服务器的位置。此URL允许连接器客户端从本地主机的端口9999上运行的RMI注册表中检索到RMI连接器服务器存根jmxrmi,并连接到RMI连接器服务器。

通过标识RMI注册表,可以创建连接器客户端。连接器客户端jmxc是由JMXConnectorFactoryconnect()方法创建的JMXConnector接口的实例。调用connect()方法时,传递了url参数和一个空环境映射。

连接到远程MBean服务器

建立RMI连接后,JMX客户端必须连接到远程MBean服务器,以便能够与远程JMX代理注册的各种MBean进行交互。

...
        
MBeanServerConnection mbsc = 
    jmxc.getMBeanServerConnection();
                
...     

通过调用JMXConnector实例jmxcgetMBeanServerConnection()方法创建了一个名为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服务器连接访问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属性,以使其发送通知。

通过代理在远程MXBean上执行操作

您可以使用与创建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方法来关闭连接。

运行自定义JMX客户端示例

此示例要求Java SE平台的版本为6。要使用自定义JMX客户端Client远程监视Main JMX代理,请按照以下步骤进行:

  1. 如果还没有这样做,请将 jmx_examples.zip 保存到你的 work_dir 目录中。
  2. 在终端窗口中使用以下命令解压示例类的捆绑包。
    unzip jmx_examples.zip
    
  3. work_dir 目录中编译示例 Java 类。
    javac com/example/*.java
    
  4. 启动 Main 应用程序,指定公开 Main 进行远程管理的属性:
    java -Dcom.sun.management.jmxremote.port=9999 \
         -Dcom.sun.management.jmxremote.authenticate=false \
         -Dcom.sun.management.jmxremote.ssl=false \ 
         com.example.Main
    

    将生成等待某些事件发生的确认。

  5. 在不同的终端窗口中启动 Client 应用程序:
    java com.example.Client
    

    显示已获取 MBeanServerConnection 的确认。

  6. 按 Enter 键。

    显示了在 Main 启动的 MBean 服务器中注册的所有 MBean 的域。

  7. 再次按 Enter 键。

    显示了在 MBean 服务器中注册的 MBean 的数量,以及所有这些 MBean 的对象名称。显示的 MBean 包括在 Java VM 中运行的所有标准平台 MXBean,以及由 Main 在 MBean 服务器中注册的 Hello MBean 和 QueueSampler MXBean。

  8. 再次按 Enter 键。

    通过 Client 调用了 Hello MBean 的操作,以下是操作的结果:

    • 将一个通知监听器添加到 Client 中以侦听来自 Main 的通知。
    • CacheSize 属性的值从 200 更改为 150。
    • 在你启动了 Main 的终端窗口中,显示了 CacheSize 属性更改的确认。
    • 在你启动了 Client 的终端窗口中,显示了来自 Main 的通知,通知 Client CacheSize 属性的更改。
    • 调用了 Hello MBean 的 sayHello 操作。
    • 在你启动了 Main 的终端窗口中,显示了消息 "Hello world"。
    • 使用值 2 和 3 作为参数调用了 Hello MBean 的 add 操作。由 Client 显示结果。
  9. 再次按 Enter 键。

    通过 Client 调用了 QueueSampler MXBean 的操作,以下是操作的结果:

    • 显示了 QueueSample 的值 dateheadsize
    • 调用了 clearQueue 操作。
  10. 再次按 Enter 键。

    Client 关闭与 MBean 服务器的连接,并显示确认。


上一页: 通过JConsole公开远程管理资源
下一页: 末尾