一、JMX的应用范围 JMX可以用来管理网络,设备,应用程序等资源,当前规范为1.1版。 二、JMX的优点 1、可以非常容易的使程序具有被管理功能 2、提供具有高度伸缩性的架构 每个JMX Agent服务可以很容易的放入到Agent中,每个JMX的实现都提供几个核心的Agent服务,你也可以自己编写服务,服务可以很容易部署,取消部署。 3、集成现有的一些管理解决方案,如SNMP 4、非常容易的利用其它java技术 5、主要提供借口,允许有不同的实现 下面这个图是JMX的结构图,通过这个图可以将JMX的层次分的更清楚些。 三、基本概念 1:MBean 通常是一个java类,它提供接口可以使这个类具有管理功能(如standard MBean,接口中定义的方法使MBean具有管理功能)。 2:MBean server 是管理MBean的一个java类,你需要向MBean server注册一个MBean后,这个MBean才会具有管理功能,MBean server还提供了查询功能和注册监听器的功能,sun提供的只是接口,不同的jmx实现中的MBean server实现也不同。 3:JMX agent agent是为了管理一系列的MBean,而提供的一系列的服务,如上图所示,通常有MBean relationships, dynamically loading classes, simple monitoring services, timers。agent可以利用Protocol adapters(例如HTTP 和SNMP)和connectors(RMI 和Jini)使不同的客户端可以访问MBean。 4:Protocol adapters 和connectors 适配器和连接器主要使不同的协议和客户端可以使用这个agent,一个agent中可以有多个Protocol adapters 和connectors,这样管理起MBean来就更方便了(有多种类型的客户端和协议可以操作MBean)。注意,Protocol adapters 和connectors通常也是MBean。 四、MBean的类型 JMX1.1相对于1.0有了很大改进,在1.1中提供4种类型的MBean,3,4两种MBean都是特殊类型的dynamic MBean。 1:standard MBean 2:dynamic MBean 3:open MBean 4:model MBean
|
=================================================================
JMX的Hello World(转)
一、JMX简介
什么是JMX?在一篇网文中是这样说的:"JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服 务实现管理",这句话我现在看着还是不知所云,云里雾里。
我们还是从JMX能给我们提供什么好处入手来理解吧。举一个应用实例:在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来写这些代码呢?
1. 程序初哥一般是写死在程序里,到要改变时就去改程序,然后再编译发布;
2. 程序熟手则一般把这些信息写在一个配置文件里(JAVA一般都是*.properties文件),到要改变时只要改配置文件,但还是重新启动系统,以便读取配置文件里的新值;
3. 程序好手则会写一个段代码,把配置值缓存起来,系统在读值的时候,先看看配置文件有没有更动。如有更改则重读一遍,否则从缓存里读取值
4. 程序高手则懂得取物为我所用,用JMX!把配置属性集中在一个类,然后写一个叫MBean的东东,再配置一下就轻松搞定了。而且JMX自动提供了一个WEB页面来给你来改变这些配置信息。
二、准备工作
JMX是一份规范,SUN依据这个规范在JDK(1.3、1.4、5.0)提供了JMX接口。而根据这个接口的实现则 有很多种,比如Weblogic的JMX实现、MX4J、JBoss的JMX实现。在SUN自己也实现了一份,不过在JDK1.4之前,这件JMX实现 (一些JAR包)是可选的,你得去它的网站上下载。JDK5.0则内嵌了进来,安装JDK5.0就可以开发基于JMX的代码了。
但JDK5.0并非包含所有SUN的关于JMX的代码,有一些工具类是排除在JDK5.0之外的。下面根据所使用的JDK版本情况,谈一谈开发环境的准备。
1、JDK1.3、1.4
去SUN网站下载SUN的JMX实现,共两个ZIP文件,下载网址:http://java.sun.com/products/JavaManagement/download.html。
(1)jmx-1_2_1-ri.zip
解压后的lib目录包含:jmxri.jar、jmxtools.jar
(2)jmx_remote-1_0_1_03-ri.zip
解压后的lib目录包含:jmxremote.jar、jmxremote_optional.jar、rmissl.jar
如果在DOS下用命令行开发,则把这五个JAR包加入到classpath系统变量中。如果你用Eclipse开发,则把JAR包加 入到项目属性的Libratries(库)引用中。
2、JDK5.0
JDK5.0的jre/lib/rt.jar已经包含了jmxri.jar、 jmxremote.jar、rmissl.jar三个包的代码。如果你用到jmxtools.jar、jmxremote_optional.jar的 类,则需要将这两个类加入到classpath或 Eclipse的项目库引用中。
3、我使用的开发环境:JDK5.0 + Eclipse3.2。
注:因为用到jmxtools.jar中的HtmlAdaptorServer类,所以将此包加入到项目库引用中。jmxremote_optional.jar暂时不用到,不管它。
三、HelloWorld实例
1、Hello是一个需要被管理的类(普通类)
什么是JMX?在一篇网文中是这样说的:"JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服 务实现管理",这句话我现在看着还是不知所云,云里雾里。
我们还是从JMX能给我们提供什么好处入手来理解吧。举一个应用实例:在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来写这些代码呢?
1. 程序初哥一般是写死在程序里,到要改变时就去改程序,然后再编译发布;
2. 程序熟手则一般把这些信息写在一个配置文件里(JAVA一般都是*.properties文件),到要改变时只要改配置文件,但还是重新启动系统,以便读取配置文件里的新值;
3. 程序好手则会写一个段代码,把配置值缓存起来,系统在读值的时候,先看看配置文件有没有更动。如有更改则重读一遍,否则从缓存里读取值
4. 程序高手则懂得取物为我所用,用JMX!把配置属性集中在一个类,然后写一个叫MBean的东东,再配置一下就轻松搞定了。而且JMX自动提供了一个WEB页面来给你来改变这些配置信息。
二、准备工作
JMX是一份规范,SUN依据这个规范在JDK(1.3、1.4、5.0)提供了JMX接口。而根据这个接口的实现则 有很多种,比如Weblogic的JMX实现、MX4J、JBoss的JMX实现。在SUN自己也实现了一份,不过在JDK1.4之前,这件JMX实现 (一些JAR包)是可选的,你得去它的网站上下载。JDK5.0则内嵌了进来,安装JDK5.0就可以开发基于JMX的代码了。
但JDK5.0并非包含所有SUN的关于JMX的代码,有一些工具类是排除在JDK5.0之外的。下面根据所使用的JDK版本情况,谈一谈开发环境的准备。
1、JDK1.3、1.4
去SUN网站下载SUN的JMX实现,共两个ZIP文件,下载网址:http://java.sun.com/products/JavaManagement/download.html。
(1)jmx-1_2_1-ri.zip
解压后的lib目录包含:jmxri.jar、jmxtools.jar
(2)jmx_remote-1_0_1_03-ri.zip
解压后的lib目录包含:jmxremote.jar、jmxremote_optional.jar、rmissl.jar
如果在DOS下用命令行开发,则把这五个JAR包加入到classpath系统变量中。如果你用Eclipse开发,则把JAR包加 入到项目属性的Libratries(库)引用中。
2、JDK5.0
JDK5.0的jre/lib/rt.jar已经包含了jmxri.jar、 jmxremote.jar、rmissl.jar三个包的代码。如果你用到jmxtools.jar、jmxremote_optional.jar的 类,则需要将这两个类加入到classpath或 Eclipse的项目库引用中。
3、我使用的开发环境:JDK5.0 + Eclipse3.2。
注:因为用到jmxtools.jar中的HtmlAdaptorServer类,所以将此包加入到项目库引用中。jmxremote_optional.jar暂时不用到,不管它。
三、HelloWorld实例
1、Hello是一个需要被管理的类(普通类)
- /**
- * @author ChenGang 2005-12-3
- */
- public class Hello implements HelloMBean {
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void printHello() {
- System.out.println("Hello World, " + name);
- }
- public void printHello(String whoName) {
- System.out.println("Hello , " + whoName);
- }
- }
2、要管理Hello则必须创建一个相应MBean,如下:
-
- /**
- * @author ChenGang 2005-12-3
- */
- public interface HelloMBean {
- public String getName();
- public void setName(String name);
- public void printHello();
- public void printHello(String whoName);
- }
3、创建一个Agent类
-
- import javax.management.MBeanServer;
- import javax.management.MBeanServerFactory;
- import javax.management.ObjectName;
- import com.sun.jdmk.comm.HtmlAdaptorServer;
- public class HelloAgent {
- public static void main(String[] args) throws Exception {
- MBeanServer server = MBeanServerFactory.createMBeanServer();
- ObjectName helloName = new ObjectName("chengang:name=HelloWorld");
- server.registerMBean(new Hello(), helloName);
- ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
- HtmlAdaptorServer adapter = new HtmlAdaptorServer();
- server.registerMBean(adapter, adapterName);
- adapter.start();
- System.out.println("start.....");
- }
- }
单击“name=HelloWorld”链接进入,出现如下页面
依照下面红线的步骤操作之后,在控制台(我用Eclipse就是console视图)得到如下输出:
在实际系统中我们可以把name变成决定数库链接池的变量,这样我就可以对系统的运行参数进行实现的监控和配置(管理)。而且也可以对一些方法(如printHello)进行远程调用了
================================================================
2、JMX简介
一、JMX简介
JMX是一种JAVA的正式规范,它主要目的是让程序且有被管理的功能,那么怎么理解所谓的“被管理”呢?试想你开发了一个软件(如WEB网 站),它是在24小时不简断运行的,那么你可能会想要“监控”这个软件的运行情况,比如收到了多少数据,有多少人登录等等。或者你又想“配置”这个软件, 比如现在访问人数比较多,你想把数据连接池设置得大一些。
当然,你也许会专门为这些管理来开发软件,但如果你借助JMX,则会发现创建这样的管理程序是如此简单。因为你无需为管理程序来开发界面,已经 有通用的JMX管理软件,如MC4J,或者是用一般都附带提供的HTML网页来管理,你要做的仅仅是将自己要被管理和监控类的按照JMX规范修改一下即可。
中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。下面将JMX的一些概念,从JMX规范转帖如下:
1.标准MBeans(Standard MBeans)设计和实现是最简单的,这类MBean使用自己的方法名作为管理接口;
2.动态MBeans(Dynamic MBeans)必须实现一个指定的接口,由于动态MBeans在运行期间暴露它们的管理接口,因
此更为灵活;
3.开放MBeans(Open MBeans)属于动态MBeans,这类MBean依靠基础数据类型来实现通用管理,并为友情用户进行
自我声明;
4.模型MBeans(Model MBeans)同样也是动态MBeans,这类MBeans是完全可配置的,在运行期间进行自我声明;它
们为资源动态工具提供一个一般性的,有默认行为的MBeans类。
在前一篇中的Hello、HelloMBean就是一个标准MBeans(Standard MBeans)。后面接下来的几篇,我们会继续介绍其他几种MBean。
JMX是一种JAVA的正式规范,它主要目的是让程序且有被管理的功能,那么怎么理解所谓的“被管理”呢?试想你开发了一个软件(如WEB网 站),它是在24小时不简断运行的,那么你可能会想要“监控”这个软件的运行情况,比如收到了多少数据,有多少人登录等等。或者你又想“配置”这个软件, 比如现在访问人数比较多,你想把数据连接池设置得大一些。
当然,你也许会专门为这些管理来开发软件,但如果你借助JMX,则会发现创建这样的管理程序是如此简单。因为你无需为管理程序来开发界面,已经 有通用的JMX管理软件,如MC4J,或者是用一般都附带提供的HTML网页来管理,你要做的仅仅是将自己要被管理和监控类的按照JMX规范修改一下即可。
中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。下面将JMX的一些概念,从JMX规范转帖如下:
二、JMX构架中的各层及相关的组件
-
- 工具层(Instrumentation Level)
(a) MBeans(标准的,动态的,开放的和模型MBeans)
(b) 通知模型:Notification、NotificationListener等类
(c) MBean元数据类:Attribute、Opreator等类 - 代理层(Agent Level)
(a) MBean Server
(b) 代理服务。如前一篇的HtmlAdaptorServer等。 - Distributed Services
- 工具层(Instrumentation Level)
1.标准MBeans(Standard MBeans)设计和实现是最简单的,这类MBean使用自己的方法名作为管理接口;
2.动态MBeans(Dynamic MBeans)必须实现一个指定的接口,由于动态MBeans在运行期间暴露它们的管理接口,因
此更为灵活;
3.开放MBeans(Open MBeans)属于动态MBeans,这类MBean依靠基础数据类型来实现通用管理,并为友情用户进行
自我声明;
4.模型MBeans(Model MBeans)同样也是动态MBeans,这类MBeans是完全可配置的,在运行期间进行自我声明;它
们为资源动态工具提供一个一般性的,有默认行为的MBeans类。
在前一篇中的Hello、HelloMBean就是一个标准MBeans(Standard MBeans)。后面接下来的几篇,我们会继续介绍其他几种MBean。
============================================================
3、Notification的使用
一、简介 Mbean之间的通信是必不可少的,Notification就起到了在Mbean之间沟通桥梁的作用。JMX notification 由四部分组成: * Notification 这个相当于一个信息包,封装了需要传递的信息 * Notification broadcaster 这相当于一个广播器,把消息广播出去 * Notification listerner 这是一个监听器,用于监听广播出来的Notification消息 * Notification filter 这是一个过滤器,过滤掉不需要的Notification消息 Notification broadcaster不需要我们实现,JMX的内部已经有了。Notification filter一般也很少用。下面的例子主要用到了Notification、Notification listerner。 二、实例 在第一篇的Hello中有一个printHello(String whoName)方法,意思根据碰到的是谁来打招呼,比如: Jack从对面走过来,说:“hi” 我们回之以礼,说:“Hello, jack” 先这需要Jack先说一个hi(相应一个操作方法),然后他说的话封装成声波(相当Notification消息包)传递 出去。然后我们还要给Jakc装上一个监听器(Hello的耳朵??^_^),这个监听器将捕捉到Jack的声波语音包,并进行相应处理,即说 “Hello, jack”。 好,我们看看如何实现的: 1、Jack类及其相应的MBean 我们把Jack写成一个MBean,如下:
* 必需继承NotificationBroadcasterSupport * 此类只有一个hi方法,方法只有两句:创建一个Notification消息包,然后将包发出去 * 如果你还要在消息包上附加其他数据,Notification还有一个setUserData方法可供使用 2、接下来是他的MBean
3、创建一个Listener,监听到的Notification消息包将由此类负责处理。
4、修改HelloAgent如下:
三、运行 1、先运行HelloAgent启动服务,再打开浏览器输入网址:http://localhost:8082/ 2、进入“name=jack”项,然后单击“hi”按钮来执行它。 四、总结 Notification和Java的事件模型是一样的,另外如果你买了《Eclipse从入门到精通》,你会发现第 22.4节也使用了和Notification和Java的事件模型相同的设计方式。Notification在我们的实际项目中也用到了,象我们现在的 给移动做的项目中(基于JMX实现),分散在各地方的工作站的日志,就是通过Notification方式,把每条产生的日志封装在 Notification中实时发回主控服务器的。有机会我会发这一系统的关于日志的设计方案写一下,它实现了对各地工作站的集中的、实时的监控,非常实 用。 |
=================================================================================
4、动态MBean:DynamicMBean
一、前言
动态MBean是在运行期才定义它的属性和方法,也就是说它有什么属性和方法是可以动态改变的。动态MBean主要利用一 些辅助类(构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类 MBeanOperationInfo)来完成这个功能,所有的动态MBean必须实现DynamicMBean接口。DynamicMBean写好后, 使用方法和第一篇文章中普通的MBean一样。
给出一个动态MBean的实例,这个实例最初动态构了一个Name属性及一个print方法,当我们执行它的print方法之后,又给此MBean新增了一个print1方法。实例的代码如下:
二、实例
1、HelloDynamic类
说明:
* 实现于接口DynamicMBean
* 借助于各种辅助类完成一个类的构造。构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类MBeanOperationInfo
* 这里所有public方法是实现于DynamicMBean的。主要提供:setAttribute设置属性、 getAttribute取得属性、setAttributes设置一组属性、getAttributes取得一组属性、invoke方法调用、 getMBeanInfo MBeanServer由这个方法得到关键的MBean类的构造信息。
2、HelloAgent类
前面说了HelloDynamic和普通MBean的使用方法是一样的,因此HelloAgent和第一篇的HelloAgent基本一样,就是把Hello改成HelloDynamic而已。为了实例完整,也一并帖出来吧。
3、运行
先运行HelloAgent。再打开浏览器,输入网址:http://localhost:8082/。单击进入“name=HelloDynamic ”项,执行print方法后再回到上一页面你会发现又多了一个print1方法。
4、总结
动态MBean的代码稍显复杂,但对于一些特殊需求的情况,它将显示出强大威力。而且它还是模型MBeans(Model MBeans)的基础。不过在一般的项目中,动态MBean还是用得比较少,所谓利器深藏之而不用,非常时方现光芒。
动态MBean是在运行期才定义它的属性和方法,也就是说它有什么属性和方法是可以动态改变的。动态MBean主要利用一 些辅助类(构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类 MBeanOperationInfo)来完成这个功能,所有的动态MBean必须实现DynamicMBean接口。DynamicMBean写好后, 使用方法和第一篇文章中普通的MBean一样。
给出一个动态MBean的实例,这个实例最初动态构了一个Name属性及一个print方法,当我们执行它的print方法之后,又给此MBean新增了一个print1方法。实例的代码如下:
二、实例
1、HelloDynamic类
- import java.lang.reflect.Constructor;
- import java.util.Iterator;
- import javax.management.Attribute;
- import javax.management.AttributeList;
- import javax.management.DynamicMBean;
- import javax.management.MBeanAttributeInfo;
- import javax.management.MBeanConstructorInfo;
- import javax.management.MBeanException;
- import javax.management.MBeanInfo;
- import javax.management.MBeanNotificationInfo;
- import javax.management.MBeanOperationInfo;
- import javax.management.MBeanParameterInfo;
- import javax.management.ReflectionException;
- /**
- * @author Sunny Peng
- * @author change by Chen.Gang, add a feature for dynamic add operation
- * @version 1.0
- */
- public class HelloDynamic implements DynamicMBean {
- //这是我们的属性名称
- private String name;
- private MBeanInfo mBeanInfo = null;
- private String className;
- private String description;
- private MBeanAttributeInfo[] attributes;
- private MBeanConstructorInfo[] constructors;
- private MBeanOperationInfo[] operations;
- MBeanNotificationInfo[] mBeanNotificationInfoArray;
- public HelloDynamic() {
- init();
- buildDynamicMBean();
- }
- private void init() {
- className = this.getClass().getName();
- description = "Simple implementation of a dynamic MBean.";
- attributes = new MBeanAttributeInfo[1];
- constructors = new MBeanConstructorInfo[1];
- operations = new MBeanOperationInfo[1];
- mBeanNotificationInfoArray = new MBeanNotificationInfo[0];
- }
- private void buildDynamicMBean() {
- //设定构造函数
- Constructor[] thisconstructors = this.getClass().getConstructors();
- constructors[0] = new MBeanConstructorInfo("HelloDynamic(): Constructs a HelloDynamic object", thisconstructors[0]);
- //设定一个属性
- attributes[0] = new MBeanAttributeInfo("Name", "java.lang.String", "Name: name string.", true, true, false);
- //operate method 我们的操作方法是print
- MBeanParameterInfo[] params = null;//无参数
- operations[0] = new MBeanOperationInfo("print", "print(): print the name", params, "void", MBeanOperationInfo.INFO);
- mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
- }
- //动态增加一个print1方法
- private void dynamicAddOperation() {
- init();
- operations = new MBeanOperationInfo[2];//设定数组为两个
- buildDynamicMBean();
- operations[1] = new MBeanOperationInfo("print1", "print1(): print the name", null, "void", MBeanOperationInfo.INFO);
- mBeanInfo = new MBeanInfo(className, description, attributes, constructors, operations, mBeanNotificationInfoArray);
- }
- public Object getAttribute(String attribute_name) {
- if (attribute_name != null)
- return null;
- if (attribute_name.equals("Name"))
- return name;
- return null;
- }
- public void setAttribute(Attribute attribute) {
- if (attribute == null)
- return;
- String Name = attribute.getName();
- Object value = attribute.getValue();
- try {
- if (Name.equals("Name")) {
- // if null value, try and see if the setter returns any exception
- if (value == null) {
- name = null;
- // if non null value, make sure it is assignable to the attribute
- } else if ((Class.forName("java.lang.String")).isAssignableFrom(value.getClass())) {
- name = (String) value;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public AttributeList getAttributes(String[] attributeNames) {
- if (attributeNames == null)
- return null;
- AttributeList resultList = new AttributeList();
- // if attributeNames is empty, return an empty result list
- if (attributeNames.length == 0)
- return resultList;
- for (int i = 0; i < attributeNames.length; i++) {
- try {
- Object value = getAttribute(attributeNames[i]);
- resultList.add(new Attribute(attributeNames[i], value));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return resultList;
- }
- public AttributeList setAttributes(AttributeList attributes) {
- if (attributes == null)
- return null;
- AttributeList resultList = new AttributeList();
- // if attributeNames is empty, nothing more to do
- if (attributes.isEmpty())
- return resultList;
- // for each attribute, try to set it and add to the result list if successfull
- for (Iterator i = attributes.iterator(); i.hasNext();) {
- Attribute attr = (Attribute) i.next();
- try {
- setAttribute(attr);
- String name = attr.getName();
- Object value = getAttribute(name);
- resultList.add(new Attribute(name, value));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return resultList;
- }
- public Object invoke(String operationName, Object params[], String signature[]) throws MBeanException, ReflectionException {
- // Check for a recognized operation name and call the corresponding operation
- if (operationName.equals("print")) {
- //具体实现我们的操作方法print
- System.out.println("Hello, " + name + ", this is HellDynamic!");
- dynamicAddOperation();
- return null;
- } else if (operationName.equals("print1")) {
- System.out.println("这是动态增加的一方法print1");
- return null;
- } else {
- // unrecognized operation name:
- throw new ReflectionException(new NoSuchMethodException(operationName), "Cannot find the operation " + operationName + " in " + className);
- }
- }
- public MBeanInfo getMBeanInfo() {
- return mBeanInfo;
- }
- }
* 实现于接口DynamicMBean
* 借助于各种辅助类完成一个类的构造。构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类MBeanOperationInfo
* 这里所有public方法是实现于DynamicMBean的。主要提供:setAttribute设置属性、 getAttribute取得属性、setAttributes设置一组属性、getAttributes取得一组属性、invoke方法调用、 getMBeanInfo MBeanServer由这个方法得到关键的MBean类的构造信息。
2、HelloAgent类
前面说了HelloDynamic和普通MBean的使用方法是一样的,因此HelloAgent和第一篇的HelloAgent基本一样,就是把Hello改成HelloDynamic而已。为了实例完整,也一并帖出来吧。
- import javax.management.MBeanServerFactory;
- import javax.management.ObjectName;
- import com.sun.jdmk.comm.HtmlAdaptorServer;
- public class HelloAgent {
- public static void main(String[] args) throws Exception {
- MBeanServer server = MBeanServerFactory.createMBeanServer();
- ObjectName helloName = new ObjectName("chengang:name=HelloDynamic");
- HelloDynamic hello = new HelloDynamic();
- server.registerMBean(hello, helloName);
- ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
- HtmlAdaptorServer adapter = new HtmlAdaptorServer();
- server.registerMBean(adapter, adapterName);
- adapter.start();
- System.out.println("start.....");
- }
- }
3、运行
先运行HelloAgent。再打开浏览器,输入网址:http://localhost:8082/。单击进入“name=HelloDynamic ”项,执行print方法后再回到上一页面你会发现又多了一个print1方法。
4、总结
动态MBean的代码稍显复杂,但对于一些特殊需求的情况,它将显示出强大威力。而且它还是模型MBeans(Model MBeans)的基础。不过在一般的项目中,动态MBean还是用得比较少,所谓利器深藏之而不用,非常时方现光芒。
==================================================================
5、用Apache的commons-modeler来辅助开发JMX
每一个MBean都要有一个接口,比如前面的Hello要有一个HelloMBean接口。要多维护一个接口,的确是件麻 烦的事。 Apache的commons-modeler利用JMX中的动态MBean原理很好的解决了这一问题,commons-modeler使用得我们可以只 写Hello,而不用写HelloMBean这个接口。不过这是有代价的,它要求我们写一个mbean的xml描述文件(唉,少了一件事,却又多出另一件 事来)。但commons-modeler还是有优点的,就是它让mbean的装配更加灵活,把多个mbean的装配都集中在一个XML文件里来了。
开始实例之前,你需要先去apache网站下载commons-modeler,以及modeler的依赖项目commons-logging。下载网 址为:http://jakarta.apache.org/site/downloads/downloads_commons.html,下载的文件 是ZIP压缩包,解压后找到commons-logging.jar和commons-modeler.jar。如果在DOS下用命令行开发,则把这两个 JAR包加入到classpath系统变量中。如果你用Eclipse开发,则把JAR包加入到项目属性的Libratries(库)引用中。
二、HelloWorld实例
我们以本系统的第一篇“1、JMX的Hello World”为例,来重新实现一次。
1、Hello.java的代码不用实现HelloMBean接口(注:为了在Eclipse上和原来的Hello文件放在不同的地方,我把新Hello放到了mbean.modelbean包),如下:
- package mbean.modelbean;
- import mbean.standard.HelloMBean;
- public class Hello{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void printHello() {
- System.out.println("Hello World, " + name);
- }
- public void printHello(String whoName) {
- System.out.println("Hello , " + whoName);
- }
- }
2、MBean不用写了,但需要写一个XML描述文件。文件名任取,这里取名为:mbeans-descriptors
-
- xml version="1.0"?>
- <mbeans-descriptors>
- <mbean name="Hello" description="the hello bean" domain="chengang" group="helloGroup" type="mbean.modelbean.Hello">
- <attribute name="name" description="a name attribute" type="java.lang.String" writeable="true"/>
- <operation name="printHello" description="a operation to print hello" impact="INFO" returnType="String"/>
- <!--</span-->mbean>
- <!--</span-->mbeans-descriptors>
这里只对 标签做一下说明:
* name mbean在xml中的唯一标识,不一定要和类同名
* description mbean的注释说明信息
* domain mbean所属域
* group mbean所属组
* type mbean的类全名(包名+类名)
* classname 指定实现代理功能的ModelMbean的全名,如果不指定则默认为BaseModelMBean
3、接下来改写HelloAgent
-
- package mbean.modelbean;
- import java.io.InputStream;
- import javax.management.MBeanServer;
- import javax.management.ObjectName;
- import javax.management.modelmbean.ModelMBean;
- import org.apache.commons.modeler.ManagedBean;
- import org.apache.commons.modeler.Registry;
- import com.sun.jdmk.comm.HtmlAdaptorServer;
- public class HelloAgent {
- public static void main(String[] args) throws Exception {
- //基于xml中的信息构建一个Registry
- Registry registry = Registry.getRegistry(null, null);
- InputStream stream = HelloAgent.class.getResourceAsStream("mbeans-descriptors.xml");
- registry.loadMetadata(stream);
- stream.close();
- //由Registry得到一个MBeanServer
- MBeanServer server = registry.getMBeanServer();
- //得到Hello在描述文件中的信息类,对应于xml文件 标签的name属性。
- ManagedBean managed = registry.findManagedBean("Hello");
- //创建ObjectName
- ObjectName helloName = new ObjectName(managed.getDomain() + ":name=HelloWorld");
- //得到ModelMBean
- ModelMBean hello = managed.createMBean(new Hello());
- //注册MBean
- server.registerMBean(hello, helloName);
- ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
- HtmlAdaptorServer adapter = new HtmlAdaptorServer();
- server.registerMBean(adapter, adapterName);
- adapter.start();
- System.out.println("start.....");
- }
- }
HelloAgent是效复杂的地方,我们来和以前的HelloAgent逐步比较一下,前后有什么不同:
(1)首先,新的HelloAgent需要将xml信息读入到Registry对象中,这是旧HelloAgent所没有的。
Registry registry = Registry.getRegistry(null, null);
InputStream stream = HelloAgent.class.getResourceAsStream("Mbeans-descriptors.xml");
registry.loadMetadata(stream);
stream.close();
(2)接着创建MBeanServer的方式也不同了
现在:MBeanServer server = registry.getMBeanServer();
以前: MBeanServer server = MBeanServerFactory.createMBeanServer();
(3)Hello相应的ObjectName创建也略不相同。主要是域名在XML描述文件里设置好了。
现在:ManagedBean managed = registry.findManagedBean("Hello");
ObjectName helloName = new ObjectName(managed.getDomain() + ":name=HelloWorld");
以前:ObjectName helloName = new ObjectName("chengang:name=HelloWorld")
(4)得到MBean的方式也不同,这里就是关键的不同点
现在:ModelMBean hello = managed.createMBean(new Hello());
以前:Hello hello = new Hello();
注 意:为什么现在要比以前多一个createMbean步骤呢,就是因为现在的写法并没有写Mbean,所以需要动态才需要生成一个。而以前就直接把new Hello()注册到mbean server就可以了,server会自动找到它的HelloMBean接口文件。
也就上面四点区别,其他代码完全一样。测试和查看效果的方法和以前一样,在此不累述了。
commons Modeler为Hello动态生成了一个MBean接口:BaseModelBean
参考资料
用Commons Modeler 开发JMX应用
====================================================
6、Model Bean
在上一节是用apache的commons-modeler来开发的一个model,只不过commons-modeler帮助我们实现了很多的代码,而 我们只需要写描述XML文件就行了。这一节,来一个实打实的Model Bean,不借助任何第三方工具包。例子还是沿用Hello这个类,以便于和以前的实现相比较。
一、Model MBean实例
1、Hello.java还是和以前的一样。这里它没有再加上一个MBean接口了,只是一个很普通的类
2、接下来是HelloAgent的写法,和以前就差一句:把“new Hello()”这一句删除了,加上了ModelMbeanUtils.createModlerMbean();
3、ModelMbeanUtils这个类是要我们自己来实现的,也是写model Bean最麻烦的地方,它主要是返回一个RequiredModelMBean类,此类主要包括了一个ModelMBeanInfo类的信息。在 ModelMBeanInfo中定义了所有对需要管理的属性和方法的描述。具体代码如下:
4、看效果的方法和以前一样,运行HelloAgent,用浏览器打开:http://localhost:8082 。效果图和standard mbean一样
二、总结
我们发现模型Mbean(Model MBean)要比标准MBean(standard mbean)复杂多了,那有什么理由让我们选择使用模型MBean吗?我认为,最大的理由就是模型MBean可以动态配置。试想一下这个应用场景:由于安 全或其他原因,系统要把某个MBean公开的可管理方法隐藏起来。这时,如果你是用标准MBean,这需要修改接口类,然后重新编译发布;如果用 Apache commons-modeler来写的模型MBean,则只需要修改XML文件就行了,不需要重新编译发布(可能要重启一下系统)。这就是模型Mbean 优势之所在了。
细心的人会发现动态MBean和这一节的模型Mbean非常相似,但它们还是有很大不同的:动态MBean没有Hello类,它要自己实现Hello类中的方法逻辑。
这里有个问题:
MBean的属性Name是可读写的,就是说可以对Name进行赋值,但是在运行的界面中对Name赋值后,调用print1Info打印出的信息是 "Hello World, null",说明Name属性并没有赋值,不知道该如何正确操作才能正确对Name赋值。
一、Model MBean实例
1、Hello.java还是和以前的一样。这里它没有再加上一个MBean接口了,只是一个很普通的类
- public class Hello{
- private String name;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public void printHello() {
- System.out.println("Hello World, " + name);
- }
- public void printHello(String whoName) {
- System.out.println("Hello , " + whoName);
- }
- }
2、接下来是HelloAgent的写法,和以前就差一句:把“new Hello()”这一句删除了,加上了ModelMbeanUtils.createModlerMbean();
- import javax.management.MBeanServer;
- import javax.management.MBeanServerFactory;
- import javax.management.ObjectName;
- import javax.management.modelmbean.RequiredModelMBean;
- import com.sun.jdmk.comm.HtmlAdaptorServer;
- public class HelloAgent {
- public static void main(String[] args) throws Exception {
- MBeanServer server = MBeanServerFactory.createMBeanServer();
- ObjectName helloName = new ObjectName("chengang:name=HelloWorld");
- //Hello hello = new Hello();
- RequiredModelMBean hello = ModelMBeanUtils.createModlerMBean();
- server.registerMBean(hello, helloName);
- ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
- HtmlAdaptorServer adapter = new HtmlAdaptorServer();
- server.registerMBean(adapter, adapterName);
- adapter.start();
- System.out.println("start.....");
- }
- }
3、ModelMbeanUtils这个类是要我们自己来实现的,也是写model Bean最麻烦的地方,它主要是返回一个RequiredModelMBean类,此类主要包括了一个ModelMBeanInfo类的信息。在 ModelMBeanInfo中定义了所有对需要管理的属性和方法的描述。具体代码如下:
- import javax.management.MBeanParameterInfo;
- import javax.management.modelmbean.ModelMBeanAttributeInfo;
- import javax.management.modelmbean.ModelMBeanInfo;
- import javax.management.modelmbean.ModelMBeanInfoSupport;
- import javax.management.modelmbean.ModelMBeanOperationInfo;
- import javax.management.modelmbean.RequiredModelMBean;
- public class ModelMBeanUtils {
- private static final boolean READABLE = true;
- private static final boolean WRITABLE = true;
- private static final boolean BOOLEAN = true;
- private static final String STRING_CLASS = "java.lang.String";
- public static RequiredModelMBean createModlerMBean() {
- RequiredModelMBean model = null;
- try {
- model = new RequiredModelMBean();
- model.setManagedResource(new Hello(), "objectReference");
- ModelMBeanInfo info = createModelMBeanInfo();
- model.setModelMBeanInfo(info);
- } catch (Exception e) {
- e.printStackTrace();
- }
- return model;
- }
- private static ModelMBeanInfo createModelMBeanInfo() {
- //
- // 属性 //
- //
- // 构造name属性信息
- ModelMBeanAttributeInfo nameAttrInfo = new ModelMBeanAttributeInfo(//
- "Name", // 属性名
- STRING_CLASS, //属性类型
- "people name", // 描述文字
- READABLE, WRITABLE, !BOOLEAN, // 读写
- null // 属性描述子
- );
- //
- // 方法 //
- //
- //构造 printHello()操作的信息
- ModelMBeanOperationInfo print1Info = new ModelMBeanOperationInfo(//
- "printHello", //
- null, //
- null, //
- "void", //
- MBeanOperationInfo.INFO, //
- null //
- );
- // 构造printHello(String whoName)操作信息
- ModelMBeanOperationInfo print2Info;
- MBeanParameterInfo[] param2 = new MBeanParameterInfo[1];
- param2[0] = new MBeanParameterInfo("whoName", STRING_CLASS, "say hello to who");
- print2Info = new ModelMBeanOperationInfo(//
- "printHello", //
- null,//
- param2,//
- "void", //
- MBeanOperationInfo.INFO, //
- null//
- );
- //
- // 最后总合 //
- //
- // create ModelMBeanInfo
- ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(//
- RequiredModelMBean.class.getName(), // MBean类
- null, // 描述文字
- new ModelMBeanAttributeInfo[] { // 所有的属性信息(数组)
- nameAttrInfo },//只有一个属性
- null, // 所有的构造函数信息
- new ModelMBeanOperationInfo[] { // 所有的操作信息(数组)
- print1Info,
- print2Info },//
- null, // 所有的通知信息(本例无)
- null//MBean描述子
- );
- return mbeanInfo;
- }
- }
4、看效果的方法和以前一样,运行HelloAgent,用浏览器打开:http://localhost:8082 。效果图和standard mbean一样
二、总结
我们发现模型Mbean(Model MBean)要比标准MBean(standard mbean)复杂多了,那有什么理由让我们选择使用模型MBean吗?我认为,最大的理由就是模型MBean可以动态配置。试想一下这个应用场景:由于安 全或其他原因,系统要把某个MBean公开的可管理方法隐藏起来。这时,如果你是用标准MBean,这需要修改接口类,然后重新编译发布;如果用 Apache commons-modeler来写的模型MBean,则只需要修改XML文件就行了,不需要重新编译发布(可能要重启一下系统)。这就是模型Mbean 优势之所在了。
细心的人会发现动态MBean和这一节的模型Mbean非常相似,但它们还是有很大不同的:动态MBean没有Hello类,它要自己实现Hello类中的方法逻辑。
这里有个问题:
MBean的属性Name是可读写的,就是说可以对Name进行赋值,但是在运行的界面中对Name赋值后,调用print1Info打印出的信息是 "Hello World, null",说明Name属性并没有赋值,不知道该如何正确操作才能正确对Name赋值。
===================================================
7、用JDK5.0的JConsole来连接MBean
前面所有看效果都是通过Html网页来看的。JDK5.0自带了一个jmx客户端,叫jconsole,位于c:/jdk/bin/jconsole.exe。我们来用用这个客户端来连接Mbean Server。
一、vm参数方式
1、还是用第一篇的那个HelloAgent,修改HelloAgent,将第一句:
MBeanServer server = MBeanServerFactory.createMBeanServer();
改为:
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
注:ManagementFactory的全路径为:java.lang.management.ManagementFactory
2、修改Eclipse的run选项,把
“-Dcom.sun.management.jmxremote=HelloAgent”这一句加入到run选项中,修改如下图:
3、运行HelloAgent,然后在Dos窗口输入“jconsole”来启到JConsole,得到如下界面。
4、单击“连接”,进入以下界面:
二、RMI方式
还是用jconsole,但方式变了。这里不需要象上面那样修改Eclipse run的vm选项。
1、还是用第一篇的HelloAgent,加上一段代码,启动一个JMXConnectorServer服务
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import com.sun.jdmk.comm.HtmlAdaptorServer;
public class HelloAgent {
public static void main(String args[]) throws Exception {
MBeanServer server = MBeanServerFactory.createMBeanServer();
ObjectName helloName = new ObjectName("chengang:name=HelloWorld");
Hello hello = new Hello();
server.registerMBean(hello, helloName);
ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082");
HtmlAdaptorServer adapter = new HtmlAdaptorServer();
server.registerMBean(adapter, adapterName);
adapter.start();
System.out.println("start.....");
// Create an RMI connector and start it
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server);
cs.start();
System.out.println("rmi start.....");
}
}
2、在Dos运行一个命令:
rmiregistry 9999
3、运行HelloAgent,然后再在dos下运行命令jconsole,得到如下界面,输入
service:jmx:rmi:///jndi/rmi://localhost:9999/server
三、总结
连接MBeanServer的方式除了Html、JConsole,还有一些第三方的客户端,比较有名的是MC4j,通过这些客户端我们可以很容易去访问MBean。这也就是我们为什么要用JMX的其中一个原因:试想如果我自己搞一套标准,势必要自己开发一个客户端,那会是一个不小的工作量。
=========================================================
8、编写程序来连接MBean
前面用Html、jconsole等方法连接上了MBeanServer,并能够通过这些界面来操纵MBean。但有时我们需要不借助这些客户端,而是在自己的程序来操纵这些MBean,这就要求我们知道如何在代码里连接MBean。
基于上一篇为jconsole而修改的例子,给出一个示例的客户端程序,基本的操作都有了:
import java.util.Iterator;
import java.util.Set;
import javax.management.Attribute;
import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class Client {
public static void main(String[] args) throws Exception {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
ObjectName mbeanName = new ObjectName("chengang:name=HelloWorld");
//把所有Domain都打印出来
System.out.println("Domains:---------------");
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
System.out.println("/tDomain[" + i + "] = " + domains[i]);
}
//MBean的总数
System.out.println("MBean count = " + mbsc.getMBeanCount());
//对name属性的操作(属性名的第一个字母要大写)
mbsc.setAttribute(mbeanName, new Attribute("Name", "Chen.Gang"));//设值
System.out.println("Name = " + mbsc.getAttribute(mbeanName, "Name"));//取值
//得到proxy代理后直接调用的方式
HelloMBean proxy = (HelloMBean) MBeanServerInvocationHandler.newProxyInstance(mbsc, mbeanName, HelloMBean.class, false);
proxy.printHello();
proxy.printHello("陈刚");
//远程调用的方式
mbsc.invoke(mbeanName, "printHello", null, null);
mbsc.invoke(mbeanName, "printHello", new Object[] { "子在川上曰" }, new String[] { String.class.getName() });
//得mbean的信息
MBeanInfo info = mbsc.getMBeanInfo(mbeanName);
System.out.println("Hello Class: " + info.getClassName());
System.out.println("Hello Attriber:" + info.getAttributes()[0].getName());
System.out.println("Hello Operation:" + info.getOperations()[0].getName());
//得到所有的MBean的ObjectName
System.out.println("all ObjectName:---------------");
Set set = mbsc.queryMBeans(null, null);
for (Iterator it = set.iterator(); it.hasNext();) {
ObjectInstance oi = (ObjectInstance) it.next();
System.out.println("/t" + oi.getObjectName());
}
//注销
//mbsc.unregisterMBean(mbeanName);
//关闭MBeanServer连接
jmxc.close();
}
}
运行后的效果如下:
Domains:---------------
Domain[0] = HelloAgent
Domain[1] = JMImplementation
Domain[2] = chengang
MBean count = 3
Name = Chen.Gang
Hello Class: mbean.connector.Hello
Hello Attriber:Name
Hello Operation:printHello
all ObjectName:---------------
chengang:name=HelloWorld
JMImplementation:type=MBeanServerDelegate
HelloAgent:name=htmladapter,port=8082
Domain[0] = HelloAgent
Domain[1] = JMImplementation
Domain[2] = chengang
MBean count = 3
Name = Chen.Gang
Hello Class: mbean.connector.Hello
Hello Attriber:Name
Hello Operation:printHello
all ObjectName:---------------
chengang:name=HelloWorld
JMImplementation:type=MBeanServerDelegate
HelloAgent:name=htmladapter,port=8082
它有两个Console输出,这里是另一个
Hello World, Chen.Gang
Hello , 陈刚
Hello World, Chen.Gang
Hello , 子在川上曰
Hello , 陈刚
Hello World, Chen.Gang
Hello , 子在川上曰
==============================================
9、基于JBoss来写MBean
前面都是用JDK自带的JMX实现来写的MBean,JMX的实现不独SUN一家,JBOSS也有自己的JMX实现。如果你使用JBOSS来做WEB服务器,那么基于JBOSS的实现来写MBean,是一个不错的选择。象我们公司就是用JBOSS的,因此所有MBean都是基于JBoss来写的。基于JBoss的MBean和基于SUN的MBean有什么不同吗?有一些不同之外,但绝大部份都一样。
import org.jboss.system.ServiceMBean;
public interface HelloWorldServiceMBean extends ServiceMBean {
String getMessage();
void setMessage(String message);
}
下面是我最早发的一篇关于JMX的文章,是我对公司所做项目的笔记,它上面的JMX例子就是基于JBOSS的。博客搬了几次家,文章删的删丢的丢,但这篇文章还保留着,简单修改一下,再帖上吧。
一、 HelloWorld实例
1、准备工作
JBOSS实现了JMX规范,这个实例是基于JBOSS来实现的。请先去下载一个JBOSS,我是jboss-3.2.6,下载地址:http://www.jboss.com/downloads/index#as。这个实例需要JBOSS的两个JAR包的支持:jboss-system-3.2.6.jar、jboss-jmx-3.2.6.jar,如果你和我一样用Eclipse来开发(推荐),那么把这个两个包加入到项目的库引用中(加入到库引用的方法参考前面两章)。
2、程序代码
假设我们有一个叫
message的属性要需要经常进行改动配置的,那么我们就把它写成一个MBean。
1、HelloWorldServiceMBean接口
在写MBean之前,我们先需要写一个MBean接口,接口里的方法都是属性的set/get方法。这个接口必须继承接口ServiceMBean。
import org.jboss.system.ServiceMBean;
public interface HelloWorldServiceMBean extends ServiceMBean {
String getMessage();
void setMessage(String message);
}
2、HelloWorldService实现类
然后写出HelloWorldServiceMBean接口的实现类HelloWorldService,这个实现类还必须继承ServiceMBeanSupport类。
这种类再简单不过了,就是属性和相应的set/get方法,EJB中叫实体类、Hibernate中叫POJO。
import org.jboss.system.ServiceMBeanSupport;
public class HelloWorldService extends ServiceMBeanSupport implements HelloWorldServiceMBean {
private String message;
public String getMessage() {
System.out.println("getMessage()=" + message);
return message;
}
public class HelloWorldService extends ServiceMBeanSupport implements HelloWorldServiceMBean {
private String message;
public String getMessage() {
System.out.println("getMessage()=" + message);
return message;
}
public void setMessage(String message) {
System.out.println("setMessage(" + message + ")");
this.message = message;
}
}
System.out.println("setMessage(" + message + ")");
this.message = message;
}
}
3、配置文件jboss-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<server>
<mbean code="example.mbean.HelloWorldService" name="www.chengang.com.cn:service=HelloWorld">
<attribute name="Message">Hello World</attribute>
</mbean>
</server>
<server>
<mbean code="example.mbean.HelloWorldService" name="www.chengang.com.cn:service=HelloWorld">
<attribute name="Message">Hello World</attribute>
</mbean>
</server>
说明:
l code项指向MBean的实现类HelloWorldService
l name项是一个名称,格式一般是:[说明性文字]:service=[类名]
l attribute是为属性设置初始值,这样当JBOSS一加载HelloWorldService类时,message属性就有了一个初始值Hello World。注意Message的第一个字母必须是大写。
l name项是一个名称,格式一般是:[说明性文字]:service=[类名]
l attribute是为属性设置初始值,这样当JBOSS一加载HelloWorldService类时,message属性就有了一个初始值Hello World。注意Message的第一个字母必须是大写。
二、将实例部署到JBOSS
在jboss-3.2.6/server/default/deploy目录下创建一个hello.sar目录,然后创建如下目录文件结构:
hello.sar
|----example
| |----mbean
| |----HelloWorldService.class (注意:是*.class,不是*.java)
| |----HelloWorldServiceMBean.class
|----META-INF
|----jboss-service.xml
|----example
| |----mbean
| |----HelloWorldService.class (注意:是*.class,不是*.java)
| |----HelloWorldServiceMBean.class
|----META-INF
|----jboss-service.xml
其他说明:
l 也可以将hello.sar目录用zip格式压缩成一个同名的hello.sar文件,放到jboss-3.2.6/server/default/deploy目录下。
l JBOSS支持热部署,也就是说你在布置这个目录时并不需要重启JBOSS。
l JBOSS支持热部署,也就是说你在布置这个目录时并不需要重启JBOSS。
三、MBean的效果 打开网址:http://127.0.0.1:8080/jmx-console/ ,出现下图
然后单击“service=HelloWorld”项打开详细页面如下:
将“HelloWorld”改成“Hello World,ChenGang”,再单击“Apply Changes”应用修改,得到如下效果:
四、其他类如何使用Messag属性
现在我们可以通过一个自动提供的WEB页面来设置Message属性了,接下来的问题是:“在其他类中应该如何得到Message的属性值”。MBean在JBoss是只保留一个MBean的实例(单例模式?),也就是说问题转成我们如何去取得这个唯一实例。例程如下:
1、创建一个使用到Message属性的类
import org.jboss.mx.util.MBeanProxyExt;
import org.jboss.mx.util.ObjectNameFactory;
public class Client {
public void go() {
HelloWorldServiceMBean mbean = (HelloWorldServiceMBean) MBeanProxyExt.create(HelloWorldServiceMBean.class, ObjectNameFactory.create(www.chengang.com.cn:service=HelloWorld));
String msg = mbean.getMessage();
System.out.println("Client.go()=" + msg);
}
}
import org.jboss.mx.util.ObjectNameFactory;
public class Client {
public void go() {
HelloWorldServiceMBean mbean = (HelloWorldServiceMBean) MBeanProxyExt.create(HelloWorldServiceMBean.class, ObjectNameFactory.create(www.chengang.com.cn:service=HelloWorld));
String msg = mbean.getMessage();
System.out.println("Client.go()=" + msg);
}
}
注意:go方法里是三句。第一句比较长,它是根据jboss-service.xml文件中设置的MBean名称,来取得此MBean在JBOSS中的实例。
2、在Mbean中加一个相应的调用Client.go的方法
在HelloWorldServiceMBean接口中加入一句:
void callGo();
在HelloWorldService类中加入现实方法:
public void callGo() {
new Client().go();
}
new Client().go();
}
3、更新布署
将三个类的class文件:Clien.class、HelloWorldServiceMBean.class、HelloWorldService.class,更新到JBOSS的hello.sar/example/mbean目录下。然后重启JBOSS。
4、查看效果
打开JBOSS提供的MBean设置页面,如下,发现多了一个callGo。
单击callGo项后的invoke按钮,得到如下的DOS输出:
五、其他说明
l 本实例仅演示了一个Message属性,你当然可以在HelloWorldService中加入更多属性,别忘了在HelloWorldServiceMBean接口也加入相应的set/get方法。
l 本实例的message属性是String类型的,但JMX也支持其他的类型,甚至是XML信息。对于jboss-service.xml中的XML信息,这时属性类型要求是org.w3c.dom.Element,JMX将它封装成了一个XML的DOM对象。
l 回顾一下,JMX也是将配置信息写在了一个文件(jboss-service.xml文件)里嘛,相对于将配置文件写到*.properties文件的方式,它似乎也没什么新鲜的地方。但通过本章实例我们可以看到JMX的一些好处:我们不用写代码去读配置文件的信息,而且JMX支持的属性类型是多种多样的(如上面说的org.w3c.dom.Element)。更重要的是JMX还提供了一整套的属性之前互相访问、互相调用的功能,这个HelloWorld实例所反映的只是冰山一角而已。
l 本实例的message属性是String类型的,但JMX也支持其他的类型,甚至是XML信息。对于jboss-service.xml中的XML信息,这时属性类型要求是org.w3c.dom.Element,JMX将它封装成了一个XML的DOM对象。
l 回顾一下,JMX也是将配置信息写在了一个文件(jboss-service.xml文件)里嘛,相对于将配置文件写到*.properties文件的方式,它似乎也没什么新鲜的地方。但通过本章实例我们可以看到JMX的一些好处:我们不用写代码去读配置文件的信息,而且JMX支持的属性类型是多种多样的(如上面说的org.w3c.dom.Element)。更重要的是JMX还提供了一整套的属性之前互相访问、互相调用的功能,这个HelloWorld实例所反映的只是冰山一角而已。
========================================================
给出一个例程吧
(1)它需要Jboss的jbossall-client.jar包的支持
(2)运行环境为Jboss3.2.6 + jdk5.0 + eclipse3.2M2。jdk5.0内置了JMX支持,如果你不是jdk5.0的话eclipse可能会报有会类找不到的错误
(3)之前必须选启动Jboss
(1)它需要Jboss的jbossall-client.jar包的支持
(2)运行环境为Jboss3.2.6 + jdk5.0 + eclipse3.2M2。jdk5.0内置了JMX支持,如果你不是jdk5.0的话eclipse可能会报有会类找不到的错误
(3)之前必须选启动Jboss
import
java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import org.jboss.jmx.adaptor.rmi.RMIAdaptor;
public class TestJMX {
public static void main(String[] args) throws Exception {
// Get RMIAdaptor Object
Properties pro = new Properties();
pro.setProperty( " java.naming.factory.initial " , " org.jnp.interfaces.NamingContextFactory " );
pro.setProperty( " java.naming.provider.url " , " jnp://localhost:1099 " );
pro.setProperty( " java.naming.factory.url.pkgs " , " org.jboss.naming:org.jnp.interfaces " );
InitialContext ic = new InitialContext(pro);
RMIAdaptor server = (RMIAdaptor) ic.lookup( " jmx/rmi/RMIAdaptor " );
// Get the MBeanInfo for the JNDIView MBean
ObjectName name = new ObjectName( " jboss:service=JNDIView " );
MBeanInfo info = server.getMBeanInfo(name);
System.out.println( " JNDIView Class: " + info.getClassName());
MBeanOperationInfo[] opInfo = info.getOperations();
System.out.println( " JNDIView Operations: " );
for ( int o = 0 ; o < opInfo.length; o ++ ) {
MBeanOperationInfo op = opInfo[o];
String returnType = op.getReturnType();
String opName = op.getName();
System.out.print( " + " + returnType + " " + opName + " ( " );
MBeanParameterInfo[] params = op.getSignature();
for ( int p = 0 ; p < params.length; p ++ ) {
MBeanParameterInfo paramInfo = params[p];
String pname = paramInfo.getName();
String type = paramInfo.getType();
if (pname.equals(type))
System.out.print(type);
else
System.out.print(type + " " + name);
if (p < params.length - 1 )
System.out.print( ' , ' );
}
System.out.println( " ) " );
}
// Get all MBeans
Set mbSet = server.queryMBeans( null , null ); //
for (Iterator it = mbSet.iterator(); it.hasNext();) {
ObjectInstance oi = (ObjectInstance) it.next();
System.out.println(oi.getObjectName());
}
}
import java.util.Properties;
import java.util.Set;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import org.jboss.jmx.adaptor.rmi.RMIAdaptor;
public class TestJMX {
public static void main(String[] args) throws Exception {
// Get RMIAdaptor Object
Properties pro = new Properties();
pro.setProperty( " java.naming.factory.initial " , " org.jnp.interfaces.NamingContextFactory " );
pro.setProperty( " java.naming.provider.url " , " jnp://localhost:1099 " );
pro.setProperty( " java.naming.factory.url.pkgs " , " org.jboss.naming:org.jnp.interfaces " );
InitialContext ic = new InitialContext(pro);
RMIAdaptor server = (RMIAdaptor) ic.lookup( " jmx/rmi/RMIAdaptor " );
// Get the MBeanInfo for the JNDIView MBean
ObjectName name = new ObjectName( " jboss:service=JNDIView " );
MBeanInfo info = server.getMBeanInfo(name);
System.out.println( " JNDIView Class: " + info.getClassName());
MBeanOperationInfo[] opInfo = info.getOperations();
System.out.println( " JNDIView Operations: " );
for ( int o = 0 ; o < opInfo.length; o ++ ) {
MBeanOperationInfo op = opInfo[o];
String returnType = op.getReturnType();
String opName = op.getName();
System.out.print( " + " + returnType + " " + opName + " ( " );
MBeanParameterInfo[] params = op.getSignature();
for ( int p = 0 ; p < params.length; p ++ ) {
MBeanParameterInfo paramInfo = params[p];
String pname = paramInfo.getName();
String type = paramInfo.getType();
if (pname.equals(type))
System.out.print(type);
else
System.out.print(type + " " + name);
if (p < params.length - 1 )
System.out.print( ' , ' );
}
System.out.println( " ) " );
}
// Get all MBeans
Set mbSet = server.queryMBeans( null , null ); //
for (Iterator it = mbSet.iterator(); it.hasNext();) {
ObjectInstance oi = (ObjectInstance) it.next();
System.out.println(oi.getObjectName());
}
}
这里有一段网上找到的代码,正好是实现了配置文件修改后重读的功能.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
/**
* @author Robbin Fan
*/
public class ConfigUtil {
private static Properties props = null;
private static File configFile = null;
private static long fileLastModified = 0L;
private static void init() {
URL url = ConfigUtil.class.getClassLoader().getResource("global.properties");
configFile = new File(url.getFile());
fileLastModified = configFile.lastModified();
props = new Properties();
load();
}
private static void load() {
try {
props.load(new FileInputStream(configFile));
fileLastModified = configFile.lastModified();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String getConfig(String key) {
if ((configFile == null) || (props == null))
init();
if (configFile.lastModified() > fileLastModified)
load();
return props.getProperty(key);
}
}
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
/**
* @author Robbin Fan
*/
public class ConfigUtil {
private static Properties props = null;
private static File configFile = null;
private static long fileLastModified = 0L;
private static void init() {
URL url = ConfigUtil.class.getClassLoader().getResource("global.properties");
configFile = new File(url.getFile());
fileLastModified = configFile.lastModified();
props = new Properties();
load();
}
private static void load() {
try {
props.load(new FileInputStream(configFile));
fileLastModified = configFile.lastModified();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String getConfig(String key) {
if ((configFile == null) || (props == null))
init();
if (configFile.lastModified() > fileLastModified)
load();
return props.getProperty(key);
}
}
如果MBean就在本地,则可以用下面的方法来获得:
ThreadPoolMBean poolMBean = (ThreadPoolMBean) MBeanProxyExt.create(ThreadPoolMBean.class, objName);
还有一种远程获得的方法(从开源代码中看到的,未验证)
ThreadPoolMBean poolMBean = (ThreadPoolMBean) MBeanServerInvocationHandler.newProxyInstance(mbeanServer, objName, ThreadPoolMBean.class, false);
* 先创建了一个MBeanServer,用来做MBean的容器
* 将Hello这个类注入到MBeanServer中,注入需要创建一个ObjectName类
* 创建一个AdaptorServer,这个类将决定MBean的管理界面,这里用最普通的Html型界面。AdaptorServer其实也是一个MBean。
* chengang:name=HelloWorld的名字是有一定规则的,格式为:“域名:name=MBean名称”,域名和MBean名称都可以任意取。
4、运行HelloAgent,然后打开网页:http://localhost:8082/,单击“name=HelloWorld”链接进入