级别: 初级 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 体系结构可以分成三层:
- 工具(instrumentation)
- 代理(agent)
- 分布式服务
在最新可用的 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 交互
 |
下载源代码
要使用本文中的示例,请确保您下载了
源代码。另外,您还须下载并安装 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 (使用
onIncButtonClicked 或
onDecButtonClicked 方法)。
ClickPanelController 通过修改
ClickPanelModel 的值使 GUI 操作与所期望的计数器操作协调。这是通过调用
ClickPanelController 的
incPanelValue() 和
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 应用程序
要注意的一件很重要的事是,整个应用程序的设计没有考虑可管理性。也就是说,应用程序中完全没有引用任何 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 工具创建了一个名叫
ClickMeterStd 的
ClickMeterInstrm 子类,它将包含 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 代理的组成
参考实现提供了一个简单的代理所需的所有元素。但是,唯一完全实现的与外部世界的连接是 HTML 协议适配器。该协议适配器允许 Web 浏览器查看并访问代理所管理的所有 MBean 的可管理元素。
让我们添加代码以配置代理并使用其协议适配器。我们将对启动 JMX 参考实现代理的支持添加到
ClickMeterStd 中。清单 3 演示了负责实例化和启动该代理的代码:
清单 3. 用于实例化和启动 JMX 代理的代码
BaseStdAgent myAgent = new BaseStdAgent();
myAgent.startAgent((Object) cms);
|
请注意
BaseStdAgent 类的使用(请参阅源代码分发版中的 BaseStdAgent.java)。本质上,代理中的逻辑包括下列程序步骤:
- 启动 MBeanServer。
- 向 MBeanServer 注册受管的 MBean。
- 启动协议适配器和连接器。
在生产编码中,将 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(
ClickMeterStd 和
HtmlAdaptorServer )编写的。同样,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 适配器。这允许我们立即访问代理。启动浏览器并指向:
您将会看到类似于图 4 的代理产生的页面:
图 4. 针对 HTML 协议适配器的主代理视图页面
我们可以看到由这个代理管理的所有 MBean。单击
name=ClickMeter。您将看到类似图 5 的页面:
图 5. 针对 HTML 协议适配器的详细的 ClickMeter MBean 视图
请注意由 MBean 公开的
PanelValue 属性以及
incPanelValue 和
decPanelValue 操作。如果您设置了重新装入时间,那么来自代理的客户机端 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 类代表的代理中执行的。
下一页
关于作者  | 
|  | Sing Li has authored this article |
对本文的评价
|