IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Java technology  >

从黑箱到企业,第 2 部分: Bean,JMX 1.1 样式

编码您自己的标准 MBean 和动态 MBean

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Sing Li (westmakaha@yahoo.com), 作家, Wrox Press

2003 年 2 月 11 日

JMX 是受欢迎的新的 Java 平台标准扩展,它支持通过现代网络管理系统或企业管理系统对设备、应用程序和服务进行管理、控制和监控。本文是顾问兼受欢迎的作家 Sing Li 所著的关于 JMX 的三部分系列文章的第二篇,在本文中,作者演示了如何快速地将工具代码添加到基于 Java 的应用程序中。

在本系列文章的 第 1 部分中,我们从以前简单的设备库管理到今天复杂而强大的网络管理系统(NMS)及企业管理系统(EMS),对网络管理的发展做了说明。JMX 已经成熟,它用可管理性方面的特性扩展了 Java 平台。它允许 NMS、EMS 和其它管理/控制应用程序管理基于 Java 平台的软件应用程序、服务和设备。JMX 的现代体系结构是分层且基于组件的,它的所有功能模块都通过良好定义的编程接口分隔(请查阅 参考资料一节)。

这一方法利用了当今最新的软件体系结构设计中的最佳实践,并以较低的实现成本提供了兼容的、可扩展的和健壮的 Java 软件可管理性的解决方案。JMX 正被迅速采用,一些最新的开放源服务器产品已经在第二代 JMX 集成中使用了。JMX 也正在成为 J2EE 1.4 草案规范中所描述的几乎所有服务器/服务组件的主要部分。

回忆一下,JMX 体系结构可以分成三层:

  1. 工具(instrumentation)
  2. 代理(agent)
  3. 分布式服务

在最新可用的 JMX 规范(撰写本文时是 1.1)中只定义了工具层和部分代理层。JMX 体系结构剩余部分的详细规范还在制订中。

在本文中,我们将使用 JMX 1.1 参考实现,将工具添加到现有的软件应用程序中。

简单的 GUI 应用程序:ClickMeter

我们的样本应用程序 ClickMeter 是基于 Swing 的 GUI 实用程序,它以典型的 MVC 设计为特色。它显示了其 GUI 上的“数字计数器”和两个按钮。单击 +按钮递增显示的数字,单击 -按钮则递减显示的数字。表 1 列出了应用程序中的文件:

表 1. ClickMeter GUI 应用程序中的文件

文件名 描述
ClickMeter.java带有我们将执行的静态 main 方法的类;它创建 GUI 框架,将其置中并显示它
ClickFrame.java包含 ClickPanel 的框架容器
ClickPanel.java单一源文件,包含用于 GUI 应用程序的三个类: ClickPanelModel (模型)、 ClickPanel (视图)和 ClickPanelController (控制器)。

负责 GUI 表示的视图类是 ClickFrame ,它是 javax.swing.JPanel 的子类。它创建 GUI 元素,将它们布置在面板上并管理用户与 GUI 的交互。ClickMeter 的 MVC 操作如图 1 所示:


图 1. ClickMeter 的 MVC 交互
图 1. ClickMeter 的 MVC 交互
下载源代码

要使用本文中的示例,请确保您下载了 源代码。另外,您还须下载并安装 JMX 1.1 参考实现(请查阅 参考资料一节以获得所有下载信息)。当然,我们假设您已经安装了 JDK 1.4 或更新版本并正在运行它。

在图 1 中, ClickPanelModel (模型)保持一个代表计数器瞬时值的 int 值(名为 val )。要访问该值,您必须通过 ClickPanelModel 类的方法。这些方法包括用于 val 变量的 set()get()increment()decrement()ClickPanel 是典型的 ClickPanelModel 的观察器。无论 ClickPanelModel 值何时更改,它都会通过调用 NotifyUpdate() 方法将更改通知给 ClickPanel

此时, ClickPanel 取出模型已更改的值并将它重新显示在包含该值的 GUI 面板上。这确保了显示在 ClickPanel 上的值始终和 ClickPanelModel 中的值保持一致。为完成这一循环, ClickPanel 管理用户和 GUI 的交互(例如,单击两个按钮中的一个),然后将所有操作都传递给 ClickPanelController (使用 onIncButtonClickedonDecButtonClicked 方法)。 ClickPanelController 通过修改 ClickPanelModel 的值使 GUI 操作与所期望的计数器操作协调。这是通过调用 ClickPanelControllerincPanelValue()decPanelValue() 方法实现的。

试验 ClickMeter:不使用 JMX

使用代码分发版中提供的 compile.bat 批处理文件来编译应用程序,或从代码子目录执行下列命令行:

javac -classpath 
        <jmx install dir>\lib\jmxri.jar;
        <jmx install dir>\lib\jmxtools.jar 
-d classes src\dwjmxservice\basic\*.java
      

使用 runmeter.bat 文件运行应用程序,或者从代码子目录执行下列命令行:

java -classpath 
        <jmx install dir>\lib\jmxri.jar;
        <jmx install dir>\lib\jmxtools.jar;
classes dwjmxservice.basic.ClickMeter
      

图 2 显示了运行的应用程序。您可以在任何时候单击这两个按钮来递增或递减计数器值。


图 2. ClickMeter GUI 应用程序
图 2. ClickMeter GUI 应用程序

要注意的一件很重要的事是,整个应用程序的设计没有考虑可管理性。也就是说,应用程序中完全没有引用任何 JMX 类,并且它不是用任何可使 JMX 代码的添加变得更容易或更困难的方法来构建的。简单地讲,这反映出它是设计良好的 Java GUI 应用程序 - 不关心对 JMX 操作的适应性。而且这也是 JMX 的本质:能很容易地将它添加到任何应用程序或软件服务器/服务,使它们立即成为是可管理的。JMX 的这一“易添加”特性的结果是很低的实现开发成本。接下来,您将看到如何能快速地将工具添加到 ClickMeter 应用程序。





回页首


规划工具

工具能添加到任何 Java 程序(包括任何软件服务、服务器或应用程序)中。工具涉及可管理的属性(特性)、操作(方法)和事件,它们可以向 JMX 代理公开(并通过这些代理向 EMS 和管理应用程序公开)。JMX 设计者首先必须确定要添加的工具。

属性类型

当您将属性工具添加到 Java 应用程序中时,只使用了 Java 对象数据类型而不要使用基本数据类型(例如,使用 java.lang.Integer 而不是 int )。参考实现不能与基本类型一起正常工作。

您可以很容易地添加工具来管理联网设备和软件服务/服务器。对于联网设备来说,属性可以是所用设备的 IP 地址和端口、所支持的协议、协议的参数等等。对设备的操作可以包括复位出厂缺省值、重新引导、固件升级等等。对于 Web 应用程序服务器来说,属性可以是每个单位时间“命中”的总数、用在服务器上的 CPU 时间总量或服务器上执行的应用程序的组合。对应用程序服务器进行的操作可以包括复位、重新引导和应用程序在服务器上的装入和卸载。

但是我们主要关心的是 ClickMeter。ClickMeter 中有什么是要受管的呢?表 2 给出了一些答案:

表 2. 受管的元素

受管的元素 类型 描述
PanelValue 属性计数器的瞬时值;和 ClickPanelModel 所保持的值一样
incPanelValue 操作计数器值加 1;和用户单击 +按钮的操作一样
decPanelValue 操作计数器值减 1;和用户单击 -按钮的操作一样

添加工具的第一步是确保可管理元素容易访问。为了帮助做到这一点,我们将一些方法添加到 ClickMeter 类中。为了保持原有的 ClickMeter 应用程序 - 让它完全与 JMX 代码无关 - 我们创建 ClickMeter 的子类,称为 ClickMeterInstrm 。该类的方法如表 3 所示:

表 3. 公开 ClickMeterInstrm 的属性和操作的方法

方法 描述
getPanelValue() 通过模型( ClickPanelModel )获取计数器的当前值
setPanelValue() 通过模型来设置计数器的当前值,因为我们知道 MVC 模式设计将确保所有视图和模型同步。
incPanelValue() 通过模型,使计数器值加 1
decPanelValue() 通过模型,使计数器值减 1

单 1 演示了 ClickMeterInstrm 类的实现:


清单 1. ClickMeterInstrm 代码
package dwjmxservice.basic;
public class ClickMeterInstrm extends ClickMeter {
  public ClickMeterInstrm() {
  }
  // code added to instrument for JMX Instrumentation
  public void setPanelValue(Integer val) {
      frame.clickPanel.myModel.setVal(val.intValue());
  }
  public Integer getPanelValue() {
   return new Integer(frame.clickPanel.myModel.getVal());
  }
  public void incPanelValue() {
  frame.clickPanel.myModel.incVal();
  }
  public void decPanelValue() {
  frame.clickPanel.myModel.decVal();
  }
}

请注意清单 1 中所示的新方法的实现如何使用 ClickPanelModel 来更改计数器的值。 setPanelValue()getPanelValue() 方法/操作提供了符合 JavaBeans 的命名约定,该约定公开了 PanelValue 特性/属性。一旦我们添加标准 Mbean 支持,这就会显得很重要。

原有的 GUI 应用程序 ClickMeter 仍是原封不动的,完全不受这次添加的影响。

既然我们已经添加了逻辑来支持对一个属性和两个操作的访问,那么我们可以添加将它们向管理代理公开的机制。要实现这一点,我们将 JMX MBean(受管的 bean,managed bean)支持添加到 ClickMeter 应用程序中。正如我们在 第 1 部分中学到的那样,MBean 实现至少有两种不同的主要样式,如表 4 所示:

表 4. 两种不同样式的 MBean 实现

MBean 实现 描述
标准所有属性、操作和事件都在编译时通过固定的管理接口进行定义。
动态Mbean 所支持的受管属性、操作和事件直到运行时才确定 - 并且可以在调用之间或者甚至在一个管理会话期间动态变化

将工具添加到 ClickMeter 中最快、最简单的方法是使用标准 MBean 实现。





回页首


实现标准 MBean

在一个标准 MBean 中,向管理代理公开的所有属性、操作和事件都在固定的接口中指定。这个接口的名称必须遵循下面这个词法模式: <服务/应用程序/设备的类名> MBean

在我们的示例中,我们已经用标准 MBean 工具创建了一个名叫 ClickMeterStdClickMeterInstrm 子类,它将包含 ClickMeter 应用程序。由于应用程序名为 ClickMeterStd ,因此标准 MBean 工具必须遵循词法模式,并命名为 ClickMeterStdMBean 。清单 2 定义了 ClickMeterStdMBean.java(可在源代码分发版中获得该文件)的接口:


清单 2. ClickMeterStdMBean 管理接口
package dwjmxservice.basic;
public interface ClickMeterStdMBean {
  public void setPanelValue(Integer inVal);
  public Integer getPanelValue();
  public void incPanelValue();
  public void decPanelValue();
}

在清单 2 中,已公开的属性作为公共的 getter 方法和 setter 方法(用于 PanelValue 属性)列出,并且操作也是公共的方法( incPanelValue()decPanelValue() 操作)。

JMX 代理将使用标准的 Java 内省(introspection)确定运行时期间 MBean 所支持的属性和操作。现在我们将创建简单的 JMX 代理。





回页首


创建简单的 JMX 代理

JMX 代理通过 MBeanServer(在 JMX 规范中定义了其接口)装载 MBean。它还提供了一组所需的代理服务(请查阅 本系列文章的第 1 部分以获得更多的详细信息),还提供了协议适配器或直接连接到 JMX 管理器或 EMS/NMS 的连接器。

日益智能化的网络设备、PC 和外围设备的出现,对这些端点的日常管理和监控方面提出了越来越高的智能化要求。而且,通过因特网处理业务的需求日益增长,从而产生了一种新的需要 EMS 支持的端点 - 即智能软件服务器/服务。

图 3 应使您想起 JMX 代理的组件化组成。在 JMX 体系结构中,代理层聚合 MBean 并公开属性、操作和事件让分布式服务层来管理。代理可以直接传递来自其聚合的 MBean 的可管理元素,或者为其自身可管理元素组提供增值特性和公开。


图 3. JMX 代理的组成
图 3. JMX 代理的组成

参考实现提供了一个简单的代理所需的所有元素。但是,唯一完全实现的与外部世界的连接是 HTML 协议适配器。该协议适配器允许 Web 浏览器查看并访问代理所管理的所有 MBean 的可管理元素。

让我们添加代码以配置代理并使用其协议适配器。我们将对启动 JMX 参考实现代理的支持添加到 ClickMeterStd 中。清单 3 演示了负责实例化和启动该代理的代码:


清单 3. 用于实例化和启动 JMX 代理的代码
    BaseStdAgent myAgent = new BaseStdAgent();
    myAgent.startAgent((Object) cms);

请注意 BaseStdAgent 类的使用(请参阅源代码分发版中的 BaseStdAgent.java)。本质上,代理中的逻辑包括下列程序步骤:

  1. 启动 MBeanServer。
  2. 向 MBeanServer 注册受管的 MBean。
  3. 启动协议适配器和连接器。

在生产编码中,将 JMX 规范所需求的大多数代理服务也作为 MBean 装入。这意味着步骤 2 还将注册代理服务的所有 MBean。事实上,就我们在此使用的 HTML 协议适配器而言,它也是 MBean。清单 4 演示了 BaseStdAgent.java 中执行步骤 1 的代码:


清单 4. BaseStdAgent 中创建和启动 MBeanServer 的代码
System.out.println("Creating the MBeanServer....");
	MBeanServer server = MBeanServerFactory.createMBeanServer();

清单 5 演示了执行步骤 2 的代码。在这个例子中,将第一个 MBean 作为 inMBean 参数传递给 BaseStdAgent 。我们还给它一个用户可读的 ObjectName


清单 5. 向 MBeanServer 注册受管的 MBean
  try {
        ObjectName tpMBeanName = new ObjectName("MBean:name=ClickMeter");
        server.registerMBean(inMBean, tpMBeanName);
      } catch (Exception e) {
         System.out.println("Cannot register ClickMeter MBean!");
         e.printStackTrace();
         return;
      }

BaseStdAgent 中最后部分的代码启动了 HTML 协议适配器,它位于 com.sun.jdmk.comm.HtmlAdaptorServer 类中。清单 6 演示了如何设置并启动协议适配器。缺省情况,它监控用于 HTML 浏览器连接的端口 8082。请注意用于注册 HTML 协议适配器的 server.registerMBean() 方法的使用,其本身就是 MBean。


清单 6. 创建和启动 HTML 协议适配器
	System.out.println("Creating an HTML protocol adaptor..");
	HtmlAdaptorServer hadaptor = new HtmlAdaptorServer();
	ObjectName adaptorName = null;
	try {
	    adaptorName = new ObjectName("Adaptor:name=hadaptor,port=8082");
	    server.registerMBean(hadaptor, adaptorName);
	} catch(Exception e) {
	    System.out.println("Cannot create the HTML protocol adaptor!");
	    e.printStackTrace();
	    return;
	}
	hadaptor.start();

以上是这个简单代理中的所有代码。如果要支持更多的代理服务,可以用和 HTML 协议适配器同样的方式向 MBeanServer 注册它们。

要注意的是,这个简单 JMX 代理的代码是独立于它要管理的 MBean( ClickMeterStdHtmlAdaptorServer )编写的。同样,MBean 代码是独立于最终用来管理它的代理编写的。这是 JMX 多层体系结构的本质。工具层的 MBean 旨在与代理层的代理逻辑松散去耦合。





回页首


通过 HTML 协议适配器连接至 JMX 代理

使用 compile.bat 文件编译具有全部工具和代理支持的 ClickMeterStd 应用程序,或者从代码子目录执行下列命令行:

javac -classpath 
        <jmx install dir>\lib\jmxri.jar;
        <jmx install dir>\lib\jmxtools.jar 
-d classes src\dwjmxservice\basic\*.java
      

使用 runstd.bat 文件启动 ClickMeterStd 应用程序,或者从代码子目录执行下列命令行:

java -classpath 
        <jmx install dir>\lib\jmxri.jar;
        <jmx install dir>\lib\jmxtools.jar;
classes dwjmxservice.basic.ClickMeterStd
      

这条命令启动了 ClickMeter 应用程序以及 JMX 代理。试一试 ClickMeter 应用程序中的按钮。因为我们添加 JMX 工具时没有更改一行 ClickMeter 代码,所以 ClickMeter 仍然像以前那样工作。但是,ClickMeter 的标准 MBean 已被装入 JMX 代理并且已经启动了 HTML 适配器。这允许我们立即访问代理。启动浏览器并指向:

http://localhost:8082/

您将会看到类似于图 4 的代理产生的页面:


图 4. 针对 HTML 协议适配器的主代理视图页面
图 4. 主代理视图

我们可以看到由这个代理管理的所有 MBean。单击 name=ClickMeter。您将看到类似图 5 的页面:


图 5. 针对 HTML 协议适配器的详细的 ClickMeter MBean 视图
图 5. 详细的 ClickMeter MBean 视图

请注意由 MBean 公开的 PanelValue 属性以及 incPanelValuedecPanelValue 操作。如果您设置了重新装入时间,那么来自代理的客户机端 JavaScript 代码将定期地轮询 PanelValue 属性的值并更新所显示的值。尝试使用 5 到 10 秒的重新装入时间并查看更新情况。您还可以单击 ClickMeter 上的 GUI 按钮来更改该值。

接下来,尝试以下操作:

  • 单击 incPanelMeter 操作以递增计数器的值。请注意我们是如何轻松地访问该操作的 - 如 JMX 管理应用程序可以通过代理做的那样。
  • 单击 decPanelMeter 操作。
  • 设置 PanelValue 属性的值。请注意它在 ClickMeter 中是如何立即被更新的。

尽管在这个例子中我们使用 HTML 协议适配器,而其它协议适配器或连接器(例如 SNMP)也可以容易地使用,并且它们将通过其它应用程序或 EMS 使我们的 ClickMeter 成为可管理的。

还记得我们说过不必将 ClickMeterStd MBean 所支持的属性和操作显式地告诉代理吗。代理实际上在运行时期间通过内省 ClickMeterStdMBean 接口发现它自己。这是使用标准 MBean 时 JMX 的标准操作。代理在运行时期间使用内省定位该管理接口(借助于必需的标准 MBean 词法命名模式)。





回页首


动态 MBean

动态 MBean 是实现 java.management.DynamicMBean 接口的 MBean。表 5 演示了该接口必须实现的方法:

表 5. 动态 MBean 接口方法

方法名 描述
getAttribute() 获取属性名称,然后将其当前值作为 Java 对象返回
getAttributes() 获取一列属性的名称,然后,如果它们的当前值可用就将其作为 Java 对象返回
setAttribute() 给属性设置特定值
setAttributes() 设置一列属性的值
invoke() 调用特定的操作;如果适用,就提供参数并支持返回值

和标准 MBean 不同的是,代理依靠 DynamicMBean 接口在运行时从 MBean 获得公开的属性、操作和事件的元数据信息。这意味着当您将工具添加到应用程序中时没必要遵循词法模式(JavaBeans 编码约定)。代理使用动态 MBean 时不需要对 MBean 执行内省。它信任从 bean 接收到的元数据,该 bean 由 getMBeanInfo() 调用。因为 MBean 在运行时期间生成这个数据,所以有可能无需重新编码静态定义的接口就可以更改该数据。开始使用动态 MBean 的最快捷的方法是使用 ModelMBean





回页首


瞬时动态 MBean 支持:ModelMBean

ModelMBean 是存在于所有 JMX 实现之中的必需的缺省 MBean 实现。JMX 规范精确地规定了如何访问 ModelMBean 实例。因为它完全由 JMX 实现来实现的,所以模型 MBean 的优点在于它的易于使用和适应性。通常在运行时,应用程序、服务、服务器或设备可以将 ModelMBean 实例实例化成其它 JMX 层的表示。

模型 MBean 始终是动态 MBean(它必须是动态的,因为没有办法让它预先知道它的用户是谁,也就是说可以不预先知道公开的属性、操作和事件)。另外,模型 MBean 为任意软件应用程序、服务、服务器或设备提供了现成可用的 MBean 外观(或封装器)。而且模型 MBean 保证是可兼容的,因为它是实现的自身代码的一部分。





回页首


使用 ModelMBean 添加工具

让我们研究一下如何使用 ModelMBean 快速地将动态 MBean 工具添加到 ClickMeter 中。我们创建一个新的 ClickMeterInstrm 子类 - 名为 ClickMeterMod 。清单 7 演示了该类的代码:


清单 7. ClickMeterMod - 使用 ModelMBean 的工具
public class ClickMeterMod extends ClickMeterInstrm  {
  public ClickMeterMod() {
  }
  public static void main(String[] args) {
    setLandF();
    ClickMeterMod cms = new ClickMeterMod();
    BaseModAgent myAgent = new BaseModAgent();
    myAgent.startAgent((Object) cms);
  }
}

请注意,清单 7 中 ClickMeterMod 类不实现任何特定的接口。它和任何编译时 JMX 需求都是完全去耦合的。这是因为我们将在运行时期间使用 JMX 参考实现中已有的模型 MBean 实现将它挂接到 JMX。这实际上是在由 BaseModAgent 类代表的代理中执行的。

下一页

关于作者

Author photo

Sing Li has authored this article




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款