分类: Java
2010-10-11 11:49:05
JMX技术提供一个简单,标准的方式管理应用程序,设备和服务等资源,一旦这些资源被创建,安装和实现,你能利用JMX的动态特性来监控和管理它们。同时你也可以用JMX来监控和管理JVM
JMX技术基于以下两个JSR开发:
* JSR 3, Java Management Extensions Instrumentation and Agent Specification
* JSR 160, Java Management Extensions Remote API
JMX规范,定义了一个架构、设计模式、APIs和服务,为应用程序和网络提供管理和监控。
使用JMX,一个给定的资源,如可管理的Beans或者MBeans,可以被一个或者更多个Java对象操作。这些MBeans注册在一个核心的管理对象
的Server上。如MBean Server,它当作一个管理的agent,能运行在大部分可用Java激活的设备上。
使用JMX agents管理资源操作必须依照规范。一个JMX agent有一个MBean Server组成,这个MBean Server,提供给MBeans 注册和一些列操作Mbeans服务,这样JMX agents直接控制资源,使得能远程控制应用程序。
这种方式能使得被操作的资源能彻底的独立于管理的底层结构,不产生任何依赖。资源可以不关心它们的管理程序如何实现。
JMX技术定义了标准的connectors(JMX connectors),使你能远程访问JMX
agents,JMX使用不同的协议提供相同的管理接口,所以管理程序可以透明的管理资源,不用考虑使用哪种通讯协议。JMX
agents也可用于支持JMX agents但与JMX规范不一致的系统和应用。
下面的图片可以看出大概结构:
JMX技术能提供给所有工业行业的Java开发者一个灵活的mbeans去操作Java代码,创建灵活的Java代理,实现分布式的管理中间件和管理,而且能平稳的集成到已经存在的管理和监控系统中去。
1 JMX使得Java应用可被管理只需要很少的投入:
一个JMX
agent能运行在大部分Java激活的设备上,因此Java应用是否可被管理与原来的设计基本没有冲突。Java应用只需要简单的嵌入一个管理对象的
Server,并在其上注册一个或多个管理Beans(MBeans)在Server上,使Server上一些功能可用。这就是从管理的基层结构获得的益
处。
2 JMX提供一个标准的方式管理Java编写的应用,系统和网络,例如:JavaEE 5的应用服务器遵循JMX架构,因此可以使用JMX技术管理。
3 JMX可以使用于JVM。你可以轻易的启动一个JMX agent 访问这内置的JVM,因此可以远程的管理和监控JVM
4 JMX提供一个可升级的,动态管理的构架。每个JMX agent服务都是独立的模块,可以根据需求,可插入管理agent中去。这种基于构件的方式意味着JMX解决方案可以在small-footprint 设备和大的 telecommunications之间切换。JMX规范提供一些核心的agent服务,另外的服务可以在管理的底层结构下自行开发,并且能动态加载, 移除和修改。
5 JMX技术利用了以前存在的标准Java技术,例如JNDI
6 使用NetBeans IDE5.0的JMX模块开发JMX应用已经非常容易了。你可以从NetBeans升级重新获得这JMX模块
7 JMX可以容易的集成已经存在的管理方案和技术。例如:JMX agents可以通过HTML浏览器管理,JMX APIs是开放的接口,任何管理系统卖主都可以利用。JMX方案可以使用Jini网络技术和Service Location Protocol (SLP)来查询服务。
server = (MBeanServer) getServletContext().getAttribute("org.apache.catalina.MBeanServer");如果通过这种方式,你获得的server为null,这说明你必须还要完成下面的工作,使你能够有权限获得系统的 MBeanServer,tomcat才会将MBeanServer的实例存放在web应用程序下属性 名"org.apache.catalina.MBeanServer"的系统变量中。
<Context path="/myapp" docBase="c:/web/" debug="9" privileged="true" reloadable="true" crossContext="true"/>2、通过JMX API中MBeanServerFactory类的createMbeanServer()的方法创建MBeanServer的实例,这样做得好处的使 JMX的实现与Web服务器无关,使代码的移植性更强。在创建完MBeanServer以后,为了让能够在管理系统中很方便的获得该 MBeanServer的引用,可将其置入application变量中(推荐),或者使用singleton设计模式的方法创建和获得。
MBeanServer server = MBeanServerFactory.createMBeanServer();
究竟采取何种方案获得MBeanServer并不十分重要,可以考虑实现的方便进行选择。
三、创建MBean
为了能够管理Web应用的资源,首先要使资源能够被管理,按照JMX规范的要求,我们将资源封装成MBean,实际上也就是为Web应用添加可管理性。
获得MBeanServer的实例以后,就可以编写自己的MBean了,根据JMX的规范,MBean有标准的和动态的两种主要类型,这里就不赘述
了,具体可以参看JMX的规范(http://)。有两种用于特殊用途的动态 MBeans:模型MBean和开放MBean。模型 MBean
(Modle MBean)提供了"现成的"MBean 实现,您可以使用它来快速地利用任何 JMX 可管理资源。它是预制的、通用的和动态的
MBean 类,并且提供了参考实现,已经包含了所有必要缺省行为的实现 - 允许您在运行时添加或覆盖需要定制的那些实现。这使得基于 Java
的、非工具化的资源能够在运行时提供保证兼容的 MBean 虚包,使它们能够通过 JMX 体系结构进行管理。
在Web应用中,资源是多元化,有运行实例,静态文件,甚至是设备或者是硬件状态,那么我们把这些资源可以分为两类,一些资源需要进行动态的管理监控
(如登陆用户数,数据库连接监控,即时日志等),一些则是静态资源,只需要进行静态的管理(系统配置文件,日志级别等),要管理这些不同类型的资源,这就
要求MBean一方面能够直接调用运行实例提供的接口进,另一方面又希望MBean自身能够提供静态资源的管理,模型MBean能够很好的满足这样的要
求,并且对于新增需要管理的资源,提供了很好的灵活性和可扩展性,因此推荐模型MBean作为Web应用首选。当然具体采用何种类型的MBean,需要结
合不同的应用,或者多种类型的MBean相结合使用。顺便提一点,采用不同类型的MBean,对于管理客户端是透明的,也就是说客户端使用一致的访问方法
来访问MBean的属性和方法,这也是JMX的一个优点。
为了更好的观察如何实现对静态资源和动态资源的管理,本文编写了两个MBean,分别实现对数据库连接属性实现静态和动态的管理。静态管理的
MBean的目的是实现对数据库配置文件修改,这样当Web应用重启后,会使用新的数据库配置,我们采用MBean的提供对资源的直接操作进行实现。动态
管理的MBean目的是对已经实例化的数据库连接对象的属性进行修改,这样在不重新启动Web应用的情况下,改变数据库连接。
1、实现管理配置文件的MBean。
JDBCConfig是一个Model
MBean,它的作用是对config.properties文件封装成MBean,该MBean包括四个属性及其相关的getter和setter和一
个save方法,其中save方法的作用是属性存入配置文件,从而实现了通过MBean直接对配置文件进行操作。这个例子中的MBean继承了
BaseModelMBean类,该类实现了javax.management.ModelMBean接口,我们可以在commons-
modeler.jar中找到BaseModelMBean类,commons-modeler.jar是tomcat4.x中使用的一个开放源码的包。
import javax.management.MBeanException; import
javax.management.RuntimeOperationsException; import
org.apache.commons.modeler.BaseModelMBean; import java.io.*; import
java.util.Properties; public class JDBCConfigMBean extends
BaseModelMBean { private String driver; private String username; private
String password; private String dburl; private static final String
CONFIG_FILEPATH = "c:\\myweb\\conf\\config.properties";
///////////////////////////////////////////////////////////////////
//constructor
///////////////////////////////////////////////////////////////////
public JDBCConfig() throws MBeanException, RuntimeOperationsException {
super(); init(); } private void init() { InputStream in = null; try {
Properties prop = new Properties(); in = new BufferedInputStream( new
FileInputStream(CONFIG_FILEPATH)); prop.load(in); driver =
prop.getProperty("driver"); dburl = prop.getProperty("dburl"); username =
prop.getProperty("username"); password = prop.getProperty("password");
in.close(); } catch (Exception e) { try { if (in != null) in.close(); }
catch (IOException e1) { e1.printStackTrace(); } e.printStackTrace(); } }
///////////////////////////////////////////////////////////////////
//getter and setter
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//public method
///////////////////////////////////////////////////////////////////
public String save() { OutputStream out = null; try { out = new
BufferedOutputStream(new FileOutputStream(CONFIG_FILEPATH)); Properties
prop = new Properties(); prop.setProperty("driver", driver);
prop.setProperty("dburl", dburl); prop.setProperty("username",
username); prop.setProperty("password", password); prop.store(out,
"---jdbc config---"); out.close(); return "save success!"; } catch
(Exception e) { try { if (out != null) out.close(); } catch (IOException
e1) { e1.printStackTrace(); } e.printStackTrace(); return "save
error!"; } } }
package com.myApp.db; import java.sql.Connection; import
java.sql.SQLException; public class DBAccess { private String driver;
private String username; private String password; private String dburl;
public Connection getConnection() { ...... } public static boolean
testConnection(String driver,String username, String password,String
dburl) { }
///////////////////////////////////////////////////////////////////
//getter and setter
/////////////////////////////////////////////////////////////////// }
第二段代码是一个Model MBean类,和前面提到的第一个Model
MBean一样,继承了BaseModelMBean,不同的是它将拥有Web应用运行时期资源实例的引用,因为所有的属性和方法都在所引用的资源实例
中,父类BaseModelMBean完成了通过反射调用该资源实例对应的属性设置方法,所以这个类的编写相当简单,我们可以在里面完成其他一些相关的方
法。
package com.myApp.db; import org.apache.commons.modeler.BaseModelMBean;
import javax.management.MBeanException; import
javax.management.RuntimeOperationsException; public class
ResInstanceMBean extends BaseModelMBean { public ResInstanceMBean ()
throws MBeanException, RuntimeOperationsException { super(); } /** other
operations **/ ..... }
第三段代码是如何实现管理数据库连接类的运行实例。
/**Web应用运行初期创建的数据库连接**/ DBAccess dbAccess = new DBAccess();
dbAccess.setDriver(); dbAccess.setPassword(); dbAccess.setUsername();
dbAccess.setDburl(); ...... /** 创建并注册管理数据库的MBean //创建mbean
ResInstanceMBean mbean= new ResInstanceMBean(); //设置MBeanInfo,这是必须的
mbean.setModelMBeanInfo(createMBeanInfo());
//设置MBean所管理的资源实例,instance为数据库连接的实例,
//"objectReference"是必须的,否则将无法将资源实例设置到MBean中,记住就行了 DBAccess instance =
getDBAccess(); mbean.setManagedResource(instance, "objectReference");
//注册mbean到MBean Server中 MBeanServer serv = getMBeanServer(); ObjectName
oname = createObjectName(mbean); serv.registerMBean(mbean, oname);
四、创建MBean描述文件
在上面第三段代码中,我们可以看到,要将MBean注册到MBean
Server中必须先创建MBeanInfo,MBean的setModelMBeanInfo()用来将MBeanInfo设置到MBean中。为了能
够灵活的获得MBean的信息,从而将MBean注册到MBeanServer,在O'Reilly出版的"java
enterprise的最佳实践"里提到,采用XML文件对MBean描述是一种非常不错的选择方案,并且提供了一个XML描述范例,因此本文也推荐在管
理Web应用也采用使用MBean描述文件的方法。实际上无论tomcat4.X,还是JBOSS,都采用使用MBean描述文件的方式创建MBean,
下面提供了一个Tomcat4.x里面的MBean描述文件方案,并用该方案描述了上述提到的两个数据库连接管理的MBean。Tomcat提供了读取该
描述文件的办法,具体可以参看Tomcat提供的帮助文档--如何使用MBean descriptor (
"
howto.html")。
<mbean-list>
<mbean name="JDBCConfigMBean"
className="com.myApp.jmx.JDBCConfigMBean"
description="the object to access database"
domain="myapp">
<attribute name="driver"
description="Jdbc driver name"
type="java.lang.String"
writeable="false"/>
<attribute name="dburl"
description="database url"
type="java.lang.String"/>
<attribute name="username"
description="Database user name"
type="java.lang.String"/>
<attribute name="password"
description="vthe user name's password"
type="java.lang.String"/>
<operation name="save"
description="save the configuration"
impact="ACTION"
returnType="java.lang.String">
</operation>
</mbean>
<mbean name="DBAccess"
className="com.myApp.jmx.ResInstanceMBean"
description="the object to access database"
domain="myapp"
type="com.myApp.db.DBAccess">
<attribute name="driver"
description="Jdbc driver name"
type="java.lang.String"
writeable="false"/>
<attribute name="dburl"
description="database url"
type="java.lang.String"/>
<attribute name="username"
description="Database user name"
type="java.lang.String"/>
<attribute name="password"
description="vthe user name's password"
type="java.lang.String"/>
<operation name="testConnection"
description="test configure attribute"
impact="ACTION"
returnType="java.lang.String">
<parameter name="driver"
description="Jdbc driver name for test"
type="java.lang.String"/>
<parameter name="username"
description="Database user name for test"
type="java.lang.String"/>
<parameter name="password"
description="the user name's password for test"
type="java.lang.String"/>
<parameter name="dburl"
description="database url for test"
type="java.lang.String"/>
</operation>
</mbean>
</mbean-list>
五、注册MBean
//注册mbean到MBean Server中 MBeanServer serv = getMBeanServer(); ObjectName oname = createObjectName(mbean); serv.registerMBean(mbean, oname);六、编写管理框架的客户端
一、JMX简介
JMX是一种JAVA的正式规范,它主要目的是让程序且有被管理的功能,那么怎么理解所谓的“被管理”呢?试想你开发了一个软件(如WEB网 站),它是在24小时不简断运行的,那么你可能会想要“监控”这个软件的运行情况,比如收到了多少数据,有多少人登录等等。或者你又想“配置”这个软件, 比如现在访问人数比较多,你想把数据连接池设置得大一些。
当然,你也许会专门为这些管理来开发软件,但如果你借助JMX,则会发现创建这样的管理程序是如此简单。因为你无需为管理程序来开发界面,已经 有通用的JMX管理软件,如MC4J,或者是用一般都附带提供的HTML网页来管理,你要做的仅仅是将自己要被管理和监控类的按照JMX规范修改一下即 可。
中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。下面将JMX的一些概念,从JMX规范转帖如下:
二、JMX构架中的各层及相关的组件
MBean中有getter和setter的就是属性,如前一篇的Hello类中Name。如果只有getter则表示该属性只读。一共有四种MBean,如下:
JMX(Java Management Extensions),顾名思义,是Java管理方案的扩展。JMX所管理的是能被Java抽象的各类应用、系统和网络,所扩展的是相应的管理和监控方案,并使之模式化和标准化。
JMX是GlassFish整个管理架构的基础。AMX是GlassFish所特有的对JMX应用的扩展,它使得在GlassFish上开发JMX应用时更加面向对象、更加简单。
本章将首先介绍JMX的背景、基本概念和用法,接着将介绍JMX技术在Java EE环境下的应用,然后将说明GlassFish对JMX技术的重要扩展(AMX),最后将说明如何在GlassFish中开发自己的MBean。
l JMX的基本概念
l Java EE的JMX应用
l GlassFish对JMX的扩展和实现
15.1.1 JMX的背景
JMX技术作为Java管理和监控的标准接口在Java SE 5.0正式被发布出来。现阶段,围绕JMX的主要Java标准Java Specification Requests(JSR)有3个:
l JSR-3,Java Management Extensions Instrumentation and Agent Specification
l JSR-160,Java Management Extensions Remote API
l JSR-77,Java 2 Platform,Enterprise Edition Management Specification
JSR-3和JSR-160都是针对Java SE平台,JSR-3是JMX的标准规范,JSR-160是JMX远程接口的规范。这两个标准将会在下个Java版本Mustang中被合并成JSR-255,具体见图15-1。
图15-1 JMX规范的演变
JSR-77针对Java EE平台,是关于企业应用的管理和监控的进一步的JMX标准。
JMX的各个相关标准定义了标准的管理模型和管理接口,为管理应用的实现提供了方便。典型的JMX管理应用包括:
l 配置查询及更改。
l 各类统计。
l 状态通知。
15.1.2 选择JMX的理由
JMX技术 已被业界广泛地使用,Sun的Sun Java System Application Server、BEA的Weblogic、IBM的Websphere等主流的Java应用服务器都相继采用和支持这个标准。JMX其实并不是什么新发明 的技术,而是对已有的几类Java技术的归纳综合。JMX被迅速广泛地采用,说明这种归纳综合迎合了实际的需求。应用JMX技术所带来的好处归纳如下:
l 以标准的方式管理Java应用、系统和网络。
l 使开发简便,借鉴并沿用了成熟简单的Java Bean的开发模式。
l 松耦合的组件开发实现了系统的可插拔性,降低了移植和维护成本。
l 可实现远程对系统的监控和管理,其中包括了系统底层的JVM。
l 对原有应用改动小,可方便地集成管理系统。
15.3.1 运用JMX技术管理Java样例ArcTest
ArcTest 是一个JDK从1.02起就附带的经典样例。ArcTest是用AWT写成的Applet。它完成的功能是根据设定的起始角度和偏移角度,画出填充或非填 充的扇形,如图15-7所示。下面将应用JMX技术对ArcTest进行改造,并对其用JMX方式管理。另可参见光盘中位于chapter15/ex1的 项目。
图15-7 Java样例ArcTest
【例15.4】应用JMX技术改造ArcTest。
用NetBeans IDE打开例程jmx_legacy,可以看到其目录结构如图15-8所示。
图15-8 例程jmx_legacy的结构
其中:
ArcTest.java是原先的ArcTest例子。
ArcTestJmx.java和ArcTestJmxMBean.java是MBean的实现。
ArcTestJmx_Agent.java实现了JMX代理。
ArcTestJmx_Manage.java实现了分布式管理应用。
可以看到,我们对原有代码未做任何改动,而且只写了很少的代码,就使这个应用的变成一个可管理的应用(具体分析参见以下各小节)。
说明:NetBeans IDE提供有JMX插件,借助这个插件可以自动创建JMX的MBean、管理应用和代理。这个插件可以通过NetBeans的Update Center获得。
15.3.2 MBean的实现
MBean的实现主要通过ArcTestJmxMBean.java和ArcTestJmx.java来完成。其中ArcTestJmx.java定义了MBean的管理接口,ArcTestJmxMBean.java具体实现了MBean的管理接口:
import java.awt.Frame;
public class ArcTestJmx implements ArcTestJmxMBean {
ArcTest arcTest;
public ArcTestJmx(ArcTest arcTest){
this.arcTest = arcTest;
}
/**
* 属性: endangle
*/
private int endAngle;
/**
* 属性: startangle
*/
private int startAngle;
//提供默认的构造函数
public ArcTestJmx() {
this(new ArcTest());
}
/**
* 读MBean的属性endAngle
*/
public int getEndAngle() {
return endAngle;
}
/**
* 写MBean的属性endAngle
*/
public void setEndAngle(int value) {
endAngle = value;
arcTest.controls.e.setText(value+"");
arcTest.controls.canvas.endAngle =value;
arcTest.controls.repaint();
}
/**
* 读MBean的属性startAngle
*/
public int getStartAngle() {
return startAngle;
}
/**
* 写MBean的属性startAngle
*/
public void setStartAngle(int value) {
startAngle = value;
arcTest.controls.s.setText(value+"");
arcTest.controls.canvas.startAngle = value;
arcTest.controls.repaint();
}
/**
* MBean的方法,初始化
*/
public void start(){
Frame f = new Frame("ArcTest");
arcTest.init();
arcTest.start();
f.add("Center", arcTest);
f.resize(300, 300);
f.show();
}
/**
* MBean的方法,以不填充的方式画出扇形
*/
public void draw() {
arcTest.controls.canvas.filled= false;
arcTest.controls.repaint();
}
/**
* MBean的方法,以填充的方式画出扇形
*/
public void fill() {
arcTest.controls.canvas.filled= true;
arcTest.controls.repaint();
}
}
15.3.3 JMX代理的实现
ArcTestJMXAgent实现了JMX代理,它完成的主要功能是注册MBean。
相关代码如下:
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
/**
* JMX agent类。启动MBean服务器,注册MBean
*/
public class ArcTestJMXAgent {
// 单一(Singleton)Agent的实例
private static ArcTestJMXAgent singleton;
public static void main(String[] args) throws Exception {
//得到MBean服务器
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
//注册MBean
ArcTestJmx MBean = new ArcTestJmx();
ObjectName MBeanName = new ObjectName(":type=ArcTestJmx");
//注册Mbesan,取名为ArcTestJMX
mbs.registerMBean(MBean, MBeanName);
//启动连接服务
//指定使用的协议和对外开发的端口,这里使用默认的RMI协议
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer connect_server =
JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
System.out.println("\n 启动RMI连接服务");
connect_server.start();
System.out.println("JMX Agent已准备好接受请求");
Thread.sleep(Long.MAX_VALUE);
}
/**
* 返回agent的唯一实例
*/
public synchronized static ArcTestJMXAgent getDefault() throws Exception
{
if(singleton == null) {
singleton = new ArcTestJMXAgent();
}
return singleton;
}
}
推荐使用默认域名。如果ObjectName未指定域名,则默认为默认域名。
15.3.4 运行实例
启动RMI服务,在命令行执行:
rmiregistry 9999
在NetBeans IDE中,先运行代理ArcTestJmx_Agent.class,提示如下:
启动RMI连接服务
JMX Agent已准备好接受请求
这时MBean服务器已经启动,装载并注册了 MBean:type=ArcTestJmx,并且在端口9999等待访问。先通过通用的JConsole来访问,启动JConsole,在 Advanced选项卡的JMX URLl栏中输入:service:jmx:rmi:///jndi/rmi://localhost:9999/server。
可以看到,ArcTestJmx已经注册在默认的域DefaultDomain下,如图15-9所示。
图15-9 通过JConsole看到的管理应用
再运行管理应用 ArcTestJmx_Manage.class,可以选择直接运行光盘中chapter15/ex1的项目。其实与JConsole一 样,ArcTestJmx_Manage也是个JMX管理应用程序。这个管理应用的任务很简单,就是启动ArcTest,将起始角度赋值为30,再用填充 画法重画。运行后可以看到如图15-10所示的效果。
图15-10 ArcTest的管理应用实现的效果
这个效果没有通过任何手工的界面操作,完全是通过编 程来实现的。相应地修改JMXServiceURL,在任何能访问本机的机器上运行管理应用ArcTestJmx_Manage,都可达到同样的效果。这 说明ArcTest已经可以被管理应用ArcTestJmx_Manage远程地管理起来。
15.3.5 分布式管理应用的实现
ArcTestJMX_Manage的完整代码如下:
import javax.management.Attribute;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/**
* JMX管理应用
*/
public class ArcTestJMX_Manage {
//JMX连接器
private JMXConnector connector;
//MBeanServerConnection
private MBeanServerConnection mbsc;
//单一实例
private static ArcTestJMX_Manage singleton;
public static void main(String[] args) throws Exception {
//管理初始化和连接远程的JMX代理
ArcTestJMX_Manage manager = ArcTestJMX_Manage.getDefault();
//对资源(这里是ArcTest程序)进行管理
manager.manageArcTest();
}
public void manageArcTest() throws Exception {
String domain = mbsc.getDefaultDomain();
ObjectName stdMBeanName =
new ObjectName(domain +":type=ArcTestJmx");
System.out.println("\nCreate ArcTestJmx MBean...");
//调用MBean方法start,无参数和返回值
mbsc.invoke(stdMBeanName, "start", null, null);
//对MBean的属性StartAngle赋值,设为30
mbsc.setAttribute(stdMBeanName,
new Attribute("StartAngle", new Integer("30")));
//调用MBean方法fill,无参数和返回值
mbsc.invoke(stdMBeanName, "fill", null, null);
}
/**
*返回JMX管理应用的单一实例
*/
public synchronized static ArcTestJMX_Manage getDefault() throws
Exception {
if(singleton == null) {
singleton = new ArcTestJMX_Manage();
singleton.connect();
}
return singleton;
}
public void connect() throws Exception {
//创建JMX Agent的URL
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
//连接JMXConnector
connector = JMXConnectorFactory.connect(url, null);
//得到MBeanServerConnection
mbsc = connector.getMBeanServerConnection();
}
public void close() throws Exception {
connector.close();
}
}
说明: MBean的命名通常使用关键字type=MBean的类名。比如例子中定义的MBean的ObjectName是type=ArcTestJmx。在后面对AMX的介绍中,可以看到GlassFish对MBean的ObjectName有着更细致的约定。
15.2.1 JMX的3层架构
JMX技术解决的是如何管理各类资源的问题。完整的JMX应用所关联的对象分为以下两类。
l 可管理资源(Manageable Resources):JMX管理的资源可以是系统、应用、服务、设备或是一个用户,只要这些对象可以通过Java语言描述。当这些资源通过MBean描述时,它们就被封装成为可管理资源。
l 管理应用(Manage Application):管理应用指各类通过JMX管理接口对可管理资源所进行的操作。
JMX要将各种资源封装成可管理资源,同时为各类管理应用访问可管理资源提供支持。三者的关联如图15-2所示。
图15-2 JMX应用所关联的两类对象
JMX应用架构被分成3个层次,分别为:装配层 (Instrumentation Level)、代理层(Agent Level),分布式服务层(Distributed Service Level),如图15-3所示。对照图15-2,中间的代理层提供类似总线的连接和可插拔服务的相关实现,装配层对应着可管理资源的相关实现,分布式服 务层对应着管理应用的相关实现。
图15-3 JMX架构图
(1) 装配层(Instrumentation Level)
装配层的主要任务就是对资源进行封装,使之成为可管理资源。所谓封装,就是通过将资源用类似Java Bean的方式描述出来。当资源以这种方式被封装成为可管理资源后,就被称作MBean(Management Bean)。
(2) 代理层(Agent Level)
代理层位于装配层和分布式服务层之间,包含 MBean服务器、注册的MBean和连接器。代理层的作用体现在内外两方面:对内它通过MBean服务器(Managed Bean Server)维护着MBean的生命周期(包括注册和注销MBean),同时为所注册的MBean提供各类服务;对外通过连接器将已注册的MBean的 管理接口暴露给外面的管理应用使用。
(3) 分布式服务层(Distributed Service Level)
分布式服务层驻留着管理应用。管理应用通过连接器 (Connector)与MBean服务器建立连接,并通过管理接口(Management Interface)去访问各个Mbean所包装的可管理资源。JMX Remote API Specification(JSR-166)对分布式服务层的应用给出了具体的规范。
JMX的3层架构的每一层都分布着不同的JMX组件,下面分别加以介绍。
15.2.2 MBean组件
MBean是Management Bean的缩写,负责将可管理资源和服务封装成类似Java Bean的形式。通过MBean的特性可以访问可管理资源的各类信息。MBean对资源的封装体现在以下几个方面:
l 属性名称及读写类型。
l 对资源的操作。
l 指定类型的通知。
说明:JVM已经默认被封装成可管理对象。可通过它去访问内置的JVM,从而远程监控并管理JVM。
MBean在JMX的3层架构中位于装配层和代理层,这两层中的MBean有着不同的作用:位于装配层的MBean被用来封装可管理资源,而位于代理层的MBean被用来封装MBean服务器提供的代理服务(比如定时器服务和监视器服务)。
从MBean的实现上来看,MBean分为两种类型:标准(Standard)MBean和动态(Dynamic) MBean。其中动态MBean又进一步分为Open MBean和Model MBean,如图15-4所示。
图15-4 MBean的分类
标准MBean适用于描述那些数据稳定且可被事先准 确定义的资源。标准MBean就是一个普通Java Bean,MBean服务器通过Java的内省(Introspection)机制来获知标准MBean的属性、事件和方法,只是这里内省所遵循的命名规 定是JMX特有的命名约定。
在各类MBean中,标准MBean的实现最为快捷方便。但在某些情况下,标准MBean并不能满足需要,比如一个资源对于不同用户有着不同的访问接口,或在不同运行状态有着不同的访问接口,这时管理接口将无法预先定义,这时就需通过动态MBean来解决问题。
动态MBean适用于描述那些要在运行时才可确切知 道的数据结构的资源。与标准 MBean不同的是,动态MBean所暴露的管理接口不必事先确定,而是可根据运行时的情况,判断生成最终的管理接口。比如用以描述配置的MBean,可 能需要通过对配置文件的分析来最终获得属性的名称和类型。
动态MBean的标志是实现了javax.manangement.DynamicBean接口。接口中的方法()所返回的就是要对外发布的管理接口。与标准MBean不一样的是,MBean服务器不是通过内省,而是通过()方法的返回值来获取动态Bean的管理接口。
动态MBean和MBean服务器所支持的接口 非常一致,这是因为MBean服务器要对标准MBean的管理接口进行内省的实现,而这也是动态MBean自身要实现的逻辑。这样,管理应用在通过 MBean服务器访问两类MBean时感觉不到任何差别,因为两者的差别在MBean服务器内部被屏蔽掉了。
Model MBean和Open MBean都是动态MBean的延伸。
(1) Model MBean预先实现了某些行为,并允许在运行过程中间进一步定制这些行为。Model MBean的标志是实现Model MBean接口,并在ModelBeanInfo对象中提供元数据的资源配置。Model MBean提供了将资源适配到MBean接口的能力。
(2) Open MBean是一类特殊的动态Mbean,它的特征是只针对特定对象,比如原始的数据类型(如int和float)和复合的数据类型。
Java Bean是最早的Java规范,它实际上是一套命名规范和设计模式。MBean沿用了Java Bean的一些命名规范并继承了Java Bean的许多特性。比如,通过内省机制得到MBean的属性和方法;通过辅助类MBeaninfo提供了更精确的关于MBean的信息;为特定需求动态 MBean所提供的对MBeaninfo的实现类似于Java Bean的Customer接口的实现;通用工具如JConsole对访问MBean的支持类似于IDE(集成开发环境)对访问Java Bean的支持。
15.2.3 MBean服务器
MBean服务器位于JMX的3层架构中的代理层, 它是代理层的核心,负责完成代理层的主要功能。MBean服务器管理着MBean的生命周期,即注册和注销,并向MBean提供各类服务,包括动态加载 (Advanced Dynamic Loading)服务、监视(Monitor)服务、定时器(Timer)服务和关联(Relation)服务。
MBean服务器和它所代理的MBean所驻留的 Java虚拟机被称作代理端(Agent Side),而管理应用所驻留的Java虚拟机被称作管理端(Manage Side)。管理端对代理端的访问多为远程访问,而MBean服务器对其代理的MBean的访问都是本地访问。
Object Name是MBean的唯一标识,它在MBean向MBean服务器中注册时指定。管理应用可以通过这个标识来寻址MBean。Object Name体现了MBean服务器关于MBean的命名机制,这一机制是管理应用和MBean之间实现松耦合的关键。Object Name的语法如下:
[domainName]:property=value[,property=value]*
可以看到,Object Name由两部分组成:域名和一组关键属性,具体说明如下。
(1) 域名(Domain Name)
关于域名的命名和Java包的约定一致,即“反向的DNS名 + 组织自定义的字串”。比如由Sun公司开发的MBean,其DNS名是sun.com,则其域名格式是com.sun.MyDomain。
(2) 关键属性(Key Properties)
关键属性是一些Key-value对,通过它们可以为MBean在指定的域中添加包括名字、类型和说明等属性,但这些属性可以不是MBean的实际属性。
【例15.1】几个Object Name的实例:
MyDomain:description=Printer,type=laser
MyDomain:description=Disk,capacity=2
DefaultDomain:description=Disk,capacity=1
DefaultDomain:description=Printer,type=ink
MBean 被MBean服务器注册并启用后,MBean服务器将解析MBean所获得的管理接口并将其暴露给外部的管理应用。管理应用必须通过MBean服务器提供 的管理接口来访问MBean,而不能直接访问MBean。MBean服务器提供的管理接口具体包含以下几部分:
l 管理注册的MBean。包括属性读写和方法调用。
l 接受MBean发出的通知。
l 实例化并注册MBean。这些MBean可以是来自驻留在代理端的类(Class),也可以是从网络或本地装载来的新类。
【例15.2】注册Mbean:
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
CacheControl MBean = new CacheControl();
//注册时,必须给MBean指定一个唯一的object name
ObjectName name = new ObjectName("com.example:type=CacheControl");
mbs.registerMBean(MBean, name);
// 也可以使用下句:
//mbs.createMBean(CacheControl.class.getName(), name);
在JMX规 范中,MBean服务器默认定义了一个叫做JMImplementation的域,并在这个域中默认地注册了一个叫 MBeanServerDelegate的MBean。这个MBean所标识和描述的就是MBean服务器。MBean服务器发出的事件通知就是由这个对 象播发出去的。
MBeanServerDelegate所定义的属性都是只读的。它的对象名是JMImplementation:type= MBeanServerDelegate。用JConsole连接到任一个MBean服务器,都可以看到这个对象,如图15-5所示。
图15-5 描述MBean服务器的Delegate MBean
15.2.4 JMX消息模型
Notification(消息)被用来特指JMX 应用中的事件。JMX消息模型所描述的是MBean之间交换信息的机制。JMX消息模型包括消息播发器、JMX消息、侦听器(Listener)和过滤器 等对象。JMX消息经过过滤器的筛选,由消息播发器发送给消息侦听器。JMX消息模型如图15-6所示。
图15-6 JMX消息模型
消息播发器和侦听器可以是任意对象,只要它们实 现了相应的接口,MBean和MBean服务器都可以充当消息播发器或侦听器的角色。侦听器需支持NotificationListener接口,这个接 口定义了事件被触发时侦听器所要完成的操作。消息播发器则要求维护一个所要通知的消息侦听器的列表,它通常实现了接口 NotificationBroadcaster或NotificationEmitter。过滤器须实现NotificationFilter 接口,并通过实现接口中的方法isNotificationEnabled(Notification notification)来决定过滤哪些消息。
JMX消息是Notification类或其子类的实例,它封装了播发器所要通知侦听器的内容和相关信息,参见表15-1。
表15-1 JMX消息的构成
属 性 |
说 明 |
Source |
消息播发器的实例引用 |
message |
对Notification的说明 |
SequenceNumber |
Notification实例的唯一标识 |
续表
属 性 |
说 明 |
TimeStamp |
时间戳。Notification何时生成 |
Type |
用点标注法表示的JMX消息类型。比如JMX.MBean.registered |
UserData |
具体的要传达的信息 |
JMX通知机制与Java Bean的事件机制主要的不同在于:JMX通知在播发器和侦听器之间的传递是统一的。这样播发器和侦听器无需预先约定事件类型,而对不同通知的差别可以通过Notification类的Type和通用的UserData来表述。
15.2.5 代理服务(Agent Service)
MBean服务器提供给注册MBean的服务被称作 JMX代理服务,它们本身也被封装成MBean的形式。代理服务位于JMX架构中的代理层。代理服务主要包括四类:动态加载(Advanced Dynamic Loading)服务、监视(Monitor)服务、定时器(Timer)服务和关联(Relation)服务。分别说明如下。
(1) 动态加载服务——通过获取包含MBean相关信息的XML文件MLet(Management Applet),实例化并注册MBean。
(2) 监视服务——监视MBean的属性变化,当属性值的变化超出预定义的范围时,相应地发出通知。根据所监视的属性,JMX定义了三类监视器。
l 计数器监视器(Counter Monitor):监视整型(Integer)类型的属性值,当数值变更幅度超出预设时触发事件。
l 度量监视器(Gauge Monitor):监视整型(Integer)或浮点类型(Floating)的属性值,当数值超出预设的上限或下限时触发事件。
l 字符串监视器(String Monitor):监视字符串(String)类型的属性值,当字符串变更时触发事件。
(3) 定时器服务——在指定时间触发事件或周期性地重复触发事件。
(4) 关联服务——定义MBean之间的关联并且维护关联的一致性。这方面的实现由包javax.management.relation提供。
15.2.6 连接器(Connector)
连接器位于JMX的3层架构中的分布式服务层。连接 器负责建立MBean服务器和管理应用之间的通信。连接器由一个驻留在代理层的连接服务器(Connector Server)和管理应用的连接客户端(Connector Client)构成。连接器屏蔽了协议的差别和协议连接的复杂性,使得管理应用和MBean服务器之间的通信过程以协议无关的方式进行。在Java SE中,RMI连接器被指定为默认的连接器。
分布式服务层中另一个用来帮助建立管理应用和 MBean服务器连接的组件是协议适配器(Protocol Adaptor)。协议适配器支持建立在某个协议之上的对MBean的访问。比如通过HTML适配器可以在Web浏览器中显示一个MBean。Java SE默认并未包含任何适配器。
【例15.3】构建到GlassFish应用服务器的JMX连接:
//构建JMX Agent URL
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:8686/jmxrmi");
Map env = new Hashtable();
//访问GlassFish应用服务器的用户名和口令
String[] creds = {"admin", "adminadmin"};
env.put(JMXConnector.CREDENTIALS, creds);
//创建JMXConnector
JMXConnector connector = JMXConnectorFactory.connect(url, env);
//得到MBeanServerConnection
MBeanServerConnection mbsc = connector.getMBeanServerConnection();
例中通过JMXServiceURL来指定建立连接所需的信息,工厂类JMXConnectorFactory通过JMXServiceURL提供的信息创建了连接器connector,通过这个连接其可以进一步访问驻留在MBean服务器中的MBean。
JMXServiceURL提供了关键的连接信息,它的格式如下:
service:jmx:protocol:sap
其中protocol为传输协议,本例中为rmi。sap是查找到连接器服务器的地址位置,本例中为///jndi/rmi://localhost:8686/jmxrmi。