一、前言
每一個MBean都要有一個接口,比如前面的Hello要有一個HelloMBean接口。要多維護一個接口,的確是件麻煩的事。Apache的commons-modeler利用JMX中的動態MBean原理很好的解決了這一問題,commons-modeler使用得我們可以只寫Hello,而不用寫HelloMBean這個接口。不過這是有代價的,它要求我們寫一個mbean的xml描述文件(唉,少了一件事,卻又多出另一件事來)。但commons-modeler還是有優點的,就是它讓mbean的裝配更加靈活,把多個mbean的裝配都集中在一個XML文件里來了。
二、HelloWorld實例
我們以本系統的第一篇“1、JMX的Hello World”為例,來重新實現一次。
1、Hello.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);
}
}
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"/>
</mbean>
</mbeans-descriptors>
這里只對<mbean>標簽做一下說明:
- 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文件<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.....");
}
}
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
參考資料