`
luotuoass
  • 浏览: 637829 次
文章分类
社区版块
存档分类
最新评论

JMX 介绍

 
阅读更多

1JMXHello World

    文/陈刚 fromwww.chengang.com.cnat <chsdate year="2005" month="12" day="3" islunardate="False" isrocdate="False" w:st="on">2005-12-3</chsdate>

地址:http://www.blogjava.net/chengang/archive/<chsdate year="2006" month="3" day="7" islunardate="False" isrocdate="False" w:st="on">2006/03/07</chsdate>/34061.html
一、JMX简介


  什么是JMX?在一篇网文中是这样说的:"JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服务实现管理",这句话我现在看着还是不知所云,云里雾里。


  我们还是从JMX能给我们提供什么好处入手来理解吧。举一个应用实例:在一个系统中常常会有一些配置信息,比如服务的IP地址,端口号什么的,那么如何来写这些代码呢?

  1. 程序初哥一般是写死在程序里,到要改变时就去改程序,然后再编译发布;

  2. 程序熟手则一般把这些信息写在一个配置文件里(JAVA一般都是*.properties文件),到要改变时只要改配置文件,但还是重新启动系统,以便读取配置文件里的新值;

  3. 程序好手则会写一个段代码,把配置值缓存起来,系统在读值的时候,先看看配置文件有没有更动。如有更改则重读一遍,否则从缓存里读取值

  4. 程序高手则懂得取物为我所用,用JMX!把配置属性集中在一个类,然后写一个叫MBean的东东,再配置一下就轻松搞定了。而且JMX自动提供了一个WEB页面来给你来改变这些配置信息。

二、准备工作


  JMX是一份规范,SUN依据这个规范在JDK1.31.45.0)提供了JMX接口。而根据这个接口的实现则有很多种,比如WeblogicJMX实现、MX4JJBossJMX实现。在SUN自己也实现了一份,不过在JDK1.4之前,这件JMX实现(一些JAR包)是可选的,你得去它的网站上下载。JDK5.0则内嵌了进来,安装JDK5.0就可以开发基于JMX的代码了。

  但JDK5.0并非包含所有SUN的关于JMX的代码,有一些工具类是排除在JDK5.0之外的。下面根据所使用的JDK版本情况,谈一谈开发环境的准备。

1JDK1.31.4

  去SUN网站下载SUNJMX实现,共两个ZIP文件,下载网址:http://java.sun.com/products/JavaManagement/download.html

1jmx-1_2_1-ri.zip

   解压后的lib目录包含:jmxri.jarjmxtools.jar

2jmx_remote-1_0_1_03-ri.zip

   解压后的lib目录包含:jmxremote.jarjmxremote_optional.jarrmissl.jar

  如果在DOS下用命令行开发,则把这五个JAR包加入到classpath系统变量中。如果你用Eclipse开发,则把JAR包加入到项目属性的Libratries(库)引用中。

2JDK5.0

  JDK5.0jre/lib/rt.jar已经包含了jmxri.jarjmxremote.jarrmissl.jar三个包的代码。如果你用到jmxtools.jarjmxremote_optional.jar的类,则需要将这两个类加入到classpathEclipse的项目库引用中。

3、我使用的开发环境:JDK5.0 Eclipse3.2

  注:因为用到jmxtools.jar中的HtmlAdaptorServer类,所以将此包加入到项目库引用中。jmxremote_optional.jar暂时不用到,不管它。


三、HelloWorld实例

1Hello是一个需要被管理的类(普通类)

/**
* @author ChenGang <chsdate year="2005" month="12" day="3" islunardate="False" isrocdate="False" w:st="on">2005-12-3</chsdate>
*/
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 <chsdate year="2005" month="12" day="3" islunardate="False" isrocdate="False" w:st="on">2005-12-3</chsdate>
*/
public interface HelloMBean {
public String getName();
public void setName(String name);
public void printHello();
public void printHello(String whoName);
}

说明:包含在MBean中方法都将是可以被管理的。MBean起名是有规范的,就是原类名后加上MBean字样。

 

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.....");
}
}

说明:

  • 先创建了一个MBeanServer,用来做MBean的容器

  • Hello这个类注入到MBeanServer中,注入需要创建一个ObjectName

  • 创建一个AdaptorServer,这个类将决定MBean的管理界面,这里用最普通的Html型界面。AdaptorServer其实也是一个MBean

  • chengang:name=HelloWorld的名字是有一定规则的,格式为:域名:name=MBean名称,域名和MBean名称都可以任意取。

4、运行HelloAgent,然后打开网页:http://localhost:8082/,单击“name=HelloWorld”链接进入,出现如下页面

<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"> <v:stroke joinstyle="miter"/> <v:formulas> <v:f eqn="if lineDrawn pixelLineWidth 0"/> <v:f eqn="sum @0 1 0"/> <v:f eqn="sum 0 0 @1"/> <v:f eqn="prod @2 1 2"/> <v:f eqn="prod @3 21600 pixelWidth"/> <v:f eqn="prod @3 21600 pixelHeight"/> <v:f eqn="sum @0 0 1"/> <v:f eqn="prod @6 1 2"/> <v:f eqn="prod @7 21600 pixelWidth"/> <v:f eqn="sum @8 21600 0"/> <v:f eqn="prod @7 21600 pixelHeight"/> <v:f eqn="sum @10 21600 0"/> </v:formulas> <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/> <o:lock v:ext="edit" aspectratio="t"/> </v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" alt="1133616990271_7574.jpg" style='width:24pt;height:24pt'/><![endif]-->1133616990271_7574.jpg

依照下面红线的步骤操作之后,在控制台(我用Eclipse就是console视图)得到如下输出:

<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75" alt="1133617125401_8322.jpg" style='width:24pt;height:24pt'/><![endif]--> alt="1133617125401_8322.jpg" v:shapes="_x0000_i1026">

五、总结

  在实际系统中我们可以把name变成决定数库链接池的变量,这样我就可以对系统的运行参数进行实现的监控和配置(管理)。而且也可以对一些方法(如printHello)进行远程调用了。

预告:下一篇将对JMX进行一些介绍,借助本篇的HelloWorld实例来灌输一些概念。

2JMX简介

一、JMX简介

  JMX是一种JAVA的正式规范,它主要目的是让程序且有被管理的功能,那么怎么理解所谓的被管理呢?试想你开发了一个软件(如WEB网站),它是在24小时不简断运行的,那么你可能会想要监控这个软件的运行情况,比如收到了多少数据,有多少人登录等等。或者你又想配置这个软件,比如现在访问人数比较多,你想把数据连接池设置得大一些。

  当然,你也许会专门为这些管理来开发软件,但如果你借助JMX,则会发现创建这样的管理程序是如此简单。因为你无需为管理程序来开发界面,已经有通用的JMX管理软件,如MC4J,或者是用一般都附带提供的HTML网页来管理,你要做的仅仅是将自己要被管理和监控类的按照JMX规范修改一下即可。

  中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。下面将JMX的一些概念,从JMX规范转帖如下:

二、JMX构架中的各层及相关的组件

  1. 工具层(Instrumentation Level
    (a) MBeans
    (标准的,动态的,开放的和模型MBeans
    (b)
    通知模型:NotificationNotificationListener等类
    (c) MBean
    元数据类:AttributeOpreator等类

  2. 代理层(Agent Level
    (a) MBean Server
    (b)
    代理服务。如前一篇的HtmlAdaptorServer等。

以下是从网上找到的两个图:

(图1<!--[if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75" alt="1133692832597_4252.jpg" style='width:24pt;height:24pt'/><![endif]-->1133692832597_4252.jpg

(图2

<!--[if gte vml 1]><v:shape id="_x0000_i1028" type="#_x0000_t75" alt="1133692869186_5136.gif" style='width:24pt;height:24pt'/><![endif]-->1133692869186_5136.gif

  MBean中有gettersetter的就是属性,如前一篇的Hello类中Name。如果只有getter则表示该属性只读。一共有四种MBean,如下:

  1. 标准MBeansStandard MBeans)设计和实现是最简单的,这类MBean使用自己的方法名作为管理接口;

  2. 动态MBeansDynamic MBeans)必须实现一个指定的接口,由于动态MBeans在运行期间暴露它们的管理接口,因此更为灵活;

  3. 开放MBeansOpen MBeans)属于动态MBeans,这类MBean依靠基础数据类型来实现通用管理,并为友情用户进行自我声明;

  4. 模型MBeansModel MBeans)同样也是动态MBeans,这类MBeans是完全可配置的,在运行期间进行自我声明;它们为资源动态工具提供一个一般性的,有默认行为的MBeans类。

  在前一篇中的HelloHelloMBean就是一个标准MBeansStandard MBeans)。后面接下来的几篇,我们会继续介绍其他几种MBean

3Notification的使用

一、简介

 

  Mbean之间的通信是必不可少的,Notification就起到了在Mbean之间沟通桥梁的作用。JMX notification 由四部分组成:

  • Notification 这个相当于一个信息包,封装了需要传递的信息

  • Notification broadcaster 这相当于一个广播器,把消息广播出去

  • Notification listerner 这是一个监听器,用于监听广播出来的Notification消息

  • Notification filter 这是一个过滤器,过滤掉不需要的Notification消息

 Notification broadcaster不需要我们实现,JMX的内部已经有了。Notification filter一般也很少用。下面的例子主要用到了NotificationNotification listerner

二、实例

 

  在第一篇的Hello中有一个printHello(String whoName)方法,意思根据碰到的是谁来打招呼,比如:

 

  Jack从对面走过来,说:“hi”

  我们回之以礼,说:“Hello, jack”

 

  首先这需要Jack先说一个hi(相应一个操作方法),然后他说的话封装成声波(相当Notification消息包)传递出去。然后我们还要给Jakc装上一个监听器(Hello的耳朵??^_^),这个监听器将捕捉到Jack的声波语音包,并进行相应处理,即说“Hello, jack”

 

  好,我们看看如何实现的:

 

1Jack类及其相应的MBean

我们把Jack写成一个MBean,如下:

import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;

public class Jack extends NotificationBroadcasterSupport implements JackMBean {
private int seq = 0;
public void hi() {
Notification n = new Notification(//
创建一个信息包
"jack.hi",//
给这个Notification起个名称
this, //
由谁发出的Notification
++seq,//
一系列通知中的序列号,可以设任意数值
System.currentTimeMillis(),//
发出时间
"Jack");//
发出的消息文本
//
发出去
sendNotification(n);
}
}

说明:

  • 必需继承NotificationBroadcasterSupport

  • 此类只有一个hi方法,方法只有两句:创建一个Notification消息包,然后将包发出去

  • 如果你还要在消息包上附加其他数据,Notification还有一个setUserData方法可供使用

2、接下来是他的MBean

public interface JackMBean {
public void hi();
}

3、创建一个Listener,监听到的Notification消息包将由此类负责处理。

import javax.management.Notification;
import javax.management.NotificationListener;
public class HelloListener implements NotificationListener {
public void handleNotification(Notification n, Object handback) {
System.out.println("type=" + n.getType());
System.out.println("source=" + n.getSource());
System.out.println("seq=" + n.getSequenceNumber());
System.out.println("send time=" + n.getTimeStamp());
System.out.println("message=" + n.getMessage());

if (handback != null) {
if (handback instanceof Hello) {
Hello hello = (Hello) handback;
hello.printHello(n.getMessage());
}
}
}
}

4、修改HelloAgent如下(加上了红色的三句):

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");
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);
Jack jack = new Jack();
server.registerMBean(jack, new ObjectName("HelloAgent:name=jack"));
jack.addNotificationListener(new HelloListener(), null, hello);
adapter.start();
System.out.println("start.....");
}
}

三、运行

1、先运行HelloAgent启动服务,再打开浏览器输入网址:http://localhost:8082/,出现如下界面。<!--[if gte vml 1]><v:shape id="_x0000_i1029" type="#_x0000_t75" alt="1133701664014_6541.jpg" style='width:24pt;height:24pt'/><![endif]-->1133701664014_6541.jpg

2、 进入“name=jack”项,然后单击“hi”按钮来执行它。这时Eclipseconsole视图显示如下:

 

<!--[if gte vml 1]><v:shape id="_x0000_i1030" type="#_x0000_t75" alt="1133702044916_7117.jpg" style='width:24pt; height:24pt'/><![endif]-->1133702044916_7117.jpg

四、总结

  NotificationJava的事件模型是一样的,另外如果你买了《Eclipse从入门到精通》,你会发现第22.4节也使用了和NotificationJava的事件模型相同的设计方式。Notification在我们的实际项目中也用到了,象我们现在的给移动做的项目中(基于JMX实现),分散在各地方的工作站的日志,就是通过Notification方式,把每条产生的日志封装在Notification中实时发回主控服务器的。有机会我会发这一系统的关于日志的设计方案写一下,它实现了对各地工作站的集中的、实时的监控,非常实用。

4、动态MBeanDynamicMBean

/陈刚 fromwww.chengang.com.cnat <chsdate year="2005" month="12" day="4" islunardate="False" isrocdate="False" w:st="on">2005-12-4</chsdate>

 

一、前言

 

  动态MBean是在运行期才定义它的属性和方法,也就是说它有什么属性和方法是可以动态改变的。动态MBean主要利用一些辅助类(构造函数类MBeanConstructorInfo、属性类MBeanAttributeInfo、方法类MBeanOperationInfo)来完成这个功能,所有的动态MBean必须实现DynamicMBean接口。DynamicMBean写好后,使用方法和第一篇文章中普通的MBean一样。

 

  给出一个动态MBean的实例,这个实例最初动态构了一个Name属性及一个print方法,当我们执行它的print方法之后,又给此MBean新增了一个print1方法。实例的代码如下:

二、实例

1HelloDynamic

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;
}
}

5、用Apachecommons-modeler来辅助开发JMX

一、前言

 

  每一个MBean都要有一个接口,比如前面的Hello要有一个HelloMBean接口。要多维护一个接口,的确是件麻烦的事。Apachecommons-modeler利用JMX中的动态MBean原理很好的解决了这一问题,commons-modeler使用得我们可以只写Hello,而不用写HelloMBean这个接口。不过这是有代价的,它要求我们写一个mbeanxml描述文件(唉,少了一件事,却又多出另一件事来)。但commons-modeler还是有优点的,就是它让mbean的装配更加灵活,把多个mbean的装配都集中在一个XML文件里来了。

  开始实例之前,你需要先去apache网站下载commons-modeler,以及modeler的依赖项目commons-logging。下载网址为:http://jakarta.apache.org/site/downloads/downloads_commons.html,下载的文件是ZIP压缩包,解压后找到commons-logging.jarcommons-modeler.jar。如果在DOS下用命令行开发,则把这两个JAR包加入到classpath系统变量中。如果你用Eclipse开发,则把JAR包加入到项目属性的Libratries(库)引用中。

二、HelloWorld实例

 我们以本系统的第一篇“1JMXHello World”为例,来重新实现一次。

 

1Hello.java的代码不变(注:为了在Eclipse上和原来的Hello文件放在不同的地方,我把新Hello放到了mbean.modelbean包),如下:

package mbean.modelbean;

import mbean.standard.HelloMBean;

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);
}
}

2MBean不用写了,但需要写一个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"/>
</mbean>
</mbeans-descriptors>

这里只对<mbean>标签做一下说明:

  • name mbeanxml中的唯一标识,不一定要和类同名

  • 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文件<mbean>标签的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.....");
}
}

6、模型BeanModel Bean

  在上一节是用apachecommons-modeler来开发的一个model,只不过commons-modeler帮助我们实现了很多的代码,而我们只需要写描述XML文件就行了。这一节,来一个实打实的Model Bean,不借助任何第三方工具包。例子还是沿用Hello这个类,以便于和以前的实现相比较。

 

一、Model MBean实例

1Hello.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.....");
}
}

3ModelMbeanUtils这个类是要我们自己来实现的,也是写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;
}
}

7、用JDK5.0JConsole来连接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、修改Eclipserun选项,把-Dcom.sun.management.jmxremote=HelloAgent这一句加入到run选项中,修改如下图:

<!--[if gte vml 1]><v:shape id="_x0000_i1031" type="#_x0000_t75" alt="1135579391260_7463.gif" style='width:24pt; height:24pt'/><![endif]-->1135579391260_7463.gif

 

3、运行HelloAgent,然后在Dos窗口输入“jconsole”来启到JConsole,得到如下界面。<!--[if gte vml 1]><v:shape id="_x0000_i1032" type="#_x0000_t75" alt="1135579573812_8685.gif" style='width:24pt; height:24pt'/><![endif]--> alt="1135579573812_8685.gif" v:shapes="_x0000_i1032"> 

4、单击连接,进入以下界面:

<!--[if gte vml 1]><v:shape id="_x0000_i1033" type="#_x0000_t75" alt="1135579720638_3644.gif" style='width:24pt; height:24pt'/><![endif]-->1135579720638_3644.gif

 

二、RMI方式

 

  还是用jconsole,但方式变了。这里不需要象上面那样修改Eclipse runvm选项。

 

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的方式除了HtmlJConsole,还有一些第三方的客户端,比较有名的是MC4j,通过这些客户端我们可以很容易去访问MBean。这也就是我们为什么要用JMX的其中一个原因:试想如果我自己搞一套标准,势必要自己开发一个客户端,那会是一个不小的工作量。

8、编写程序来连接MBean

  前面用Htmljconsole等方法连接上了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());

 //得到所有的MBeanObjectName
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

 

它有两个Console输出,这里是另一个

Hello World, Chen.Gang
Hello ,
陈刚
Hello World, Chen.Gang
Hello ,
子在川上曰

9、基于JBoss来写MBean

 

  前面都是用JDK自带的JMX实现来写的MBeanJMX的实现不独SUN一家,JBOSS也有自己的JMX实现。如果你使用JBOSS来做WEB服务器,那么基于JBOSS的实现来写MBean,是一个不错的选择。象我们公司就是用JBOSS的,因此所有MBean都是基于JBoss来写的。基于JBossMBean和基于SUNMBean有什么不同吗?有一些不同之外,但绝大部份都一样。

 

  下面是我最早发的一篇关于JMX的文章,是我对公司所做项目的笔记,它上面的JMX例子就是基于JBOSS的。博客搬了几次家,文章删的删丢的丢,但这篇文章还保留着,简单修改一下,再帖上吧。

一、HelloWorld实例

1、准备工作

  JBOSS实现了JMX规范,这个实例是基于JBOSS来实现的。请先去下载一个JBOSS,我是jboss-<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">3.2.6</chsdate>,下载地址:http://www.jboss.com/downloads/index#as。这个实例需要JBOSS的两个JAR包的支持:jboss-system-3.2.6.jarjboss-jmx-3.2.6.jar,如果你和我一样用Eclipse来开发(推荐),那么把这个两个包加入到项目的库引用中(加入到库引用的方法参考前面两章)。

2、程序代码

  假设我们有一个叫message的属性要需要经常进行改动配置的,那么我们就把它写成一个MBean

1HelloWorldServiceMBean接口

  在写MBean之前,我们先需要写一个MBean接口,接口里的方法都是属性的set/get方法。这个接口必须继承接口ServiceMBean


import org.jboss.system.ServiceMBean;
public interface HelloWorldServiceMBean extends ServiceMBean {
String getMessage();
void setMessage(String message);
}

2HelloWorldService实现类

  然后写出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 void setMessage(String 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>

说明:

lcode项指向MBean的实现类HelloWorldService
lname项是一个名称,格式一般是:[说明性文字]:service=[类名]
lattribute是为属性设置初始值,这样当JBOSS一加载HelloWorldService类时,message属性就有了一个初始值Hello World。注意Message的第一个字母必须是大写。

二、将实例部署到JBOSS

  在jboss-<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">3.2.6</chsdate>/server/default/deploy目录下创建一个hello.sar目录,然后创建如下目录文件结构:

hello.sar
|----example
| |----mbean
| |----HelloWorldService.class(
注意:是*.class,不是*.java)
| |----HelloWorldServiceMBean.class
|----META-INF
|----jboss-service.xml

其他说明:

l也可以将hello.sar目录用zip格式压缩成一个同名的hello.sar文件,放到jboss-<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">3.2.6</chsdate>/server/default/deploy目录下。
lJBOSS支持热部署,也就是说你在布置这个目录时并不需要重启JBOSS

三、MBean的效果

打开网址:http://127.0.0.1:8080/jmx-console/ ,出现下图

<!--[if gte vml 1]><v:shape id="_x0000_i1034" type="#_x0000_t75" alt="1135588829669_6124.jpg" style='width:24pt;height:24pt'/><![endif]-->1135588829669_6124.jpg然后单击“service=HelloWorld”项打开详细页面如下:

<!--[if gte vml 1]><v:shape id="_x0000_i1035" type="#_x0000_t75" alt="1135588871713_5327.jpg" style='width:24pt;height:24pt'/><![endif]-->1135588871713_5327.jpg

将“HelloWorld”改成“Hello WorldChenGang”,再单击“Apply Changes”应用修改,得到如下效果:

<!--[if gte vml 1]><v:shape id="_x0000_i1036" type="#_x0000_t75" alt="1135588893639_3324.jpg" style='width:24pt;height:24pt'/><![endif]-->1135588893639_3324.jpg

四、其他类如何使用Messag属性

  现在我们可以通过一个自动提供的WEB页面来设置Message属性了,接下来的问题是:“在其他类中应该如何得到Message的属性值”。MBeanJBoss是只保留一个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);
}
}

注意:go方法里是三句。第一句比较长,它是根据jboss-service.xml文件中设置的MBean名称,来取得此MBeanJBOSS中的实例。

2、在Mbean中加一个相应的调用Client.go的方法

 在HelloWorldServiceMBean接口中加入一句:

void callGo();

HelloWorldService类中加入现实方法:

public void callGo() {
new Client().go();
}

3、更新布署

将三个类的class文件:Clien.classHelloWorldServiceMBean.classHelloWorldService.class,更新到JBOSShello.sar/example/mbean目录下。然后重启JBOSS

4、查看效果

打开JBOSS提供的MBean设置页面,如下,发现多了一个callGo

<!--[if gte vml 1]><v:shape id="_x0000_i1037" type="#_x0000_t75" alt="1135589421532_8527.jpg" style='width:24pt;height:24pt'/><![endif]-->1135589421532_8527.jpg

单击callGo项后的invoke按钮,得到如下的DOS输出:

<!--[if gte vml 1]><v:shape id="_x0000_i1038" type="#_x0000_t75" alt="1135589435968_2575.jpg" style='width:24pt;height:24pt'/><![endif]-->1135589435968_2575.jpg

五、其他说明

l本实例仅演示了一个Message属性,你当然可以在HelloWorldService中加入更多属性,别忘了在HelloWorldServiceMBean接口也加入相应的set/get方法。
l本实例的message属性是String类型的,但JMX也支持其他的类型,甚至是XML信息。对于jboss-service.xml中的XML信息,这时属性类型要求是org.w<chmetcnv unitname="C" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">3c</chmetcnv>.dom.ElementJMX将它封装成了一个XMLDOM对象。
l回顾一下,JMX也是将配置信息写在了一个文件(jboss-service.xml文件)里嘛,相对于将配置文件写到*.properties文件的方式,它似乎也没什么新鲜的地方。但通过本章实例我们可以看到JMX的一些好处:我们不用写代码去读配置文件的信息,而且JMX支持的属性类型是多种多样的(如上面说的org.w<chmetcnv unitname="C" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on">3c</chmetcnv>.dom.Element)。更重要的是JMX还提供了一整套的属性之前互相访问、互相调用的功能,这个HelloWorld实例所反映的只是冰山一角而已。

六、参考资料:http://www.huihoo.com/java/jmx/jmx_base.html 

七、作者简介

陈刚,广西桂林人,著作有《Eclipse从入门到精通》
您可以通过其博客了解更多信息和文章:http://www.chenGang.com.cn

分享到:
评论

相关推荐

    jmx介绍和使用

    jmx的简单介绍和使用,包含一些简单的代码示例,看完基本能了解jmx并使用。

    JMX小例子以及介绍

    JMX小例子以及介绍 JMX小例子以及介绍 JMX小例子以及介绍

    JMX实战 JMX开发

    书中不仅有对于基础知识的介绍,还有对于JMX开发中重大的体系架构问题的深入探讨,总结了大量JMX开发中的设计模式,并讨论了框架、安全性与性能等等。书中提供了几个典型的例子,兼顾各种开发平台,这些例子的代码...

    jmx技术介绍(ppt)

    有关jmx技术培训的ppt 比较基础的讲解了jmx技术

    《jmx技术介绍》配套源代码

    《jmx技术介绍》配套源代码 示例代码多而又简单清晰

    JMX规范介绍

    java管理扩展(The Java Management extensions )也叫做JMX规范,定义了一个java网络管理、监控和应用程序服务的架构,以及其中的设计模式和API。这个章节将介绍所有这些内容,并展示JMX涉及的广阔领域。

    JMX1.4规范中文版

    这篇文档是对JMX 的一个介绍,给出了定JMX 设备层,代理层和部署层服务的规范。 它不是编程手册或者教程,而是希望读者可以对JMX 架构、设计模式和编程接口有一定程 度的理解。 完整的JMX 规范是由本书和API 文档...

    jmx 实现远程连接tomcat

    本文档主要介绍了jmx连接T远程监控tomcat的详细配置,文档包含了一些配置的详细图片和需要注意的内容

    论文研究-JMX技术在网络监控中的应用.pdf

    分析了当前网络监控中面临的主要问题,提出了采用JMX方案来解决的办法。介绍了JMX的技术特点,并采用该技术实现了IP网络管理中的网络监控任务的调配和管理。

    Spring jmx

    这是俞黎明一份关于jmx的介绍,以及如何结合spring开发jmx,是根据他的ppt改成的。

    Java分布式应用学习笔记09JMX-MBean的介绍

    Java分布式应用学习笔记09JMX-MBean的介绍

    Tomcat开启JMX服务方法介绍

    主要介绍了Tomcat开启JMX服务方法的相关内容,小编觉得挺不错的,在这里给大家分享一下,需要的朋友可以参考。

    史上最全的jmx运用讲义

    本节代码详细说明文件上传功能的开发流程,介绍知识点如下: 1. 文件上传页面和显示上传成功页面代码内容。 2. UploadAction类中实现上传功能方法和上传文件属性介绍。 3. struts.xml中UploadAction配置,以及...

    jmxtools-1.2.1.jar+jmxri-1.2.1.jar.zip

    需要的自会需要,介绍没用,亲测可用。 javax.jms包,sun的JMS接口规范包,官方已经不提供了,这里给2分,给大家下载。

    jmx-1_2_1-bin,jmxremote-1_0_1-bin,com.sun.jdmk.comm.HtmlAdaptorServer

    csdn有一个下载包含HtmlAdaptorServer这个class,不过不知道是不是官方的,而且跟网上介绍的资料不一样,所以自己去oracle官网找着下载下来分享给大家,只要2分啦 包含资源文件为如下: jmx_remote-1_0_1_03-ri.zip jmx-1...

    JMX入门教程

    JMX入门教程,详细介绍JMX的常用类和方法

    JMX1.4规范中文版.pdf

    JMX 技术是应用越来越广泛的技术,已经是JDK 标准的一部分。它的最新规范是1.4,这是介绍JMX的资料

    JMX技术学习非常好的资料

    概要的介绍了JMX技术,适合于初学者!通过该资料的学习,可以基本熟悉JMX的基本知识和技术架构!

    基于JMX的IT系统管理关键技术研究与实现

    基于JMX的IT系统管理关键技术研究与实现,详细介绍了使用jmx的方法

Global site tag (gtag.js) - Google Analytics