JMX一步步来
http://www.quanlei.com/tag/jmx
http://www.blogjava.net/chengang/category/8015.html
[JMX一步步來] 1、JMX的Hello World
文/陳剛 from www.chengang.com.cn at 2005-12-3一、JMX簡介
什么是JMX?在一篇網文中是這樣說的:"JMX(Java Management Extensions)是一個為應用程序植入管理功能的框架。JMX是一套標準的代理和服務,實際上,用戶可以在任何Java應用程序中使用這些代理和服務實現管理",這句話我現在看著還是不知所云,云里霧里。
我們還是從JMX能給我們提供什么好處入手來理解吧。舉一個應用實例:在一個系統中常常會有一些配置信息,比如服務的IP地址,端口號什么的,那么如何來寫這些代碼呢?
二、準備工作
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的代碼了。
三、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); } 說明:包含在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名稱都可以任意取。
依照下面紅線的步驟操作之后,在控制臺(我用Eclipse就是console視圖)得到如下輸出:
五、總結
在實際系統中我們可以把name變成決定數庫鏈接池的變量,這樣我就可以對系統的運行參數進行實現的監控和配置(管理)。而且也可以對一些方法(如printHello)進行遠程調用了。
預告:下一篇將對JMX進行一些介紹,借助本篇的HelloWorld實例來灌輸一些概念。
作者簡介
陳剛,廣西桂林人,著作有《Eclipse從入門到精通》
您可以通過其博客了解更多信息和文章:http://www.chenGang.com.cn
?
[JMX一步步來] 2、JMX簡介
文/陳剛 from www.chengang.com.cn at 2005-12-4一、JMX簡介
JMX是一種JAVA的正式規范,它主要目的是讓程序且有被管理的功能,那么怎么理解所謂的“被管理”呢?試想你開發了一個軟件(如WEB網站),它是在24小時不簡斷運行的,那么你可能會想要“監控”這個軟件的運行情況,比如收到了多少數據,有多少人登錄等等。或者你又想“配置”這個軟件,比如現在訪問人數比較多,你想把數據連接池設置得大一些。
當然,你也許會專門為這些管理來開發軟件,但如果你借助JMX,則會發現創建這樣的管理程序是如此簡單。因為你無需為管理程序來開發界面,已經有通用的JMX管理軟件,如MC4J,或者是用一般都附帶提供的HTML網頁來管理,你要做的僅僅是將自己要被管理和監控類的按照JMX規范修改一下即可。
中間件軟件WebLogic的管理頁面就是基于JMX開發的,而JBoss則整個系統都基于JMX構架。下面將JMX的一些概念,從JMX規范轉帖如下:
二、JMX構架中的各層及相關的組件
????(a) MBeans(標準的,動態的,開放的和模型MBeans)
????(b) 通知模型:Notification、NotificationListener等類
????(c) MBean元數據類:Attribute、Opreator等類
????(a) MBean Server
????(b) 代理服務。如前一篇的HtmlAdaptorServer等。
以下是從網上找到的兩個圖:
(圖1)
(圖2)
MBean中有getter和setter的就是屬性,如前一篇的Hello類中Name。如果只有getter則表示該屬性只讀。一共有四種MBean,如下:
[JMX一步步來] 3、Notification的使用
文/陳剛 from www.chengang.com.cn at 2005-12-4 一、簡介 Mbean之間的通信是必不可少的,Notification就起到了在Mbean之間溝通橋梁的作用。JMX notification 由四部分組成:- Notification 這個相當于一個信息包,封裝了需要傳遞的信息
- Notification broadcaster 這相當于一個廣播器,把消息廣播出去
- Notification listerner 這是一個監聽器,用于監聽廣播出來的Notification消息
- Notification filter 這是一個過濾器,過濾掉不需要的Notification消息
二、實例 在第一篇的Hello中有一個printHello(String whoName)方法,意思根據碰到的是誰來打招呼,比如: Jack從對面走過來,說:“hi” 我們回之以禮,說:“Hello, jack” 首先這需要Jack先說一個hi(相應一個操作方法),然后他說的話封裝成聲波(相當Notification消息包)傳遞出去。然后我們還要給Jakc裝上一個監聽器(Hello的耳朵??^_^),這個監聽器將捕捉到Jack的聲波語音包,并進行相應處理,即說“Hello, jack”。 好,我們看看如何實現的: 1、Jack類及其相應的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方法可供使用
四、總結
Notification和Java的事件模型是一樣的,另外如果你買了《Eclipse從入門到精通》,你會發現第22.4節也使用了和Notification和Java的事件模型相同的設計方式。Notification在我們的實際項目中也用到了,象我們現在的給移動做的項目中(基于JMX實現),分散在各地方的工作站的日志,就是通過Notification方式,把每條產生的日志封裝在Notification中實時發回主控服務器的。有機會我會發這一系統的關于日志的設計方案寫一下,它實現了對各地工作站的集中的、實時的監控,非常實用。
作者簡介
陳剛,廣西桂林人,著作有《Eclipse從入門到精通》
您可以通過其博客了解更多信息和文章:http://www.chenGang.com.cn
[JMX一步步來] 4、動態MBean:DynamicMBean
文/陳剛? from www.chengang.com.cn at 2005-12-4 一、前言 動態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 我們的操作方法是printMBeanParameterInfo[] 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 exceptionif (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 listif (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 doif (attributes.isEmpty())return resultList;// for each attribute, try to set it and add to the result list if successfullfor (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 operationif (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類的構造信息。
?
?
[JMX一步步來] 5、用Apache的commons-modeler來輔助開發JMX
文/陳剛? from www.chengang.com.cn at 2005-12-13 一、前言 每一個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的代碼不變(注:為了在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?
???? 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
[JMX一步步來] 6、模型Bean:Model Bean
文/陳剛? from www.chengang.com.cn at 2005-12-26 在上一節是用apache的commons-modeler來開發的一個model,只不過commons-modeler幫助我們實現了很多的代碼,而我們只需要寫描述XML文件就行了。這一節,來一個實打實的Model Bean,不借助任何第三方工具包。例子還是沿用Hello這個類,以便于和以前的實現相比較。 一、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一樣,就不再帖出來了,去第一篇去看吧http://blog.sohu.com/members/somebody076/545896.html 二、總結 我們發現模型Mbean(Model MBean)要比標準MBean(standard mbean)復雜多了,那有什么理由讓我們選擇使用模型MBean嗎?我認為,最大的理由就是模型MBean可以動態配置。試想一下這個應用場景:由于安全或其他原因,系統要把某個MBean公開的可管理方法隱藏起來。這時,如果你是用標準MBean,這需要修改接口類,然后重新編譯發布;如果用Apache commons-modeler來寫的模型MBean,則只需要修改XML文件就行了,不需要重新編譯發布(可能要重啟一下系統)。這就是模型Mbean優勢之所在了。
細心的人會發現動態MBean和這一節的模型Mbean非常相似,但它們還是有很大不同的:動態MBean沒有Hello類,它要自己實現Hello類中的方法邏輯。
?
[JMX一步步來] 7、用JDK5.0的JConsole來連接MBean
文/陳剛? from www.chengang.com.cn at 2005-12-26 前面所有看效果都是通過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的其中一個原因:試想如果我自己搞一套標準,勢必要自己開發一個客戶端,那會是一個不小的工作量。[JMX一步步來] 8、編寫程序來連接MBean
文/陳剛? from www.chengang.com.cn at 2005-12-26 前面用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的ObjectNameSystem.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 , 子在川上曰
[JMX一步步來] 9、基于JBoss來寫MBean
文/陳剛? from www.chengang.com.cn at 2005-12-26 前面都是用JDK自帶的JMX實現來寫的MBean,JMX的實現不獨SUN一家,JBOSS也有自己的JMX實現。如果你使用JBOSS來做WEB服務器,那么基于JBOSS的實現來寫MBean,是一個不錯的選擇。象我們公司就是用JBOSS的,因此所有MBean都是基于JBoss來寫的。基于JBoss的MBean和基于SUN的MBean有什么不同嗎?有一些不同之外,但絕大部份都一樣。 下面是我最早發的一篇關于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 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>
說明:
l?code項指向MBean的實現類HelloWorldService
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
其他說明:
l?也可以將hello.sar目錄用zip格式壓縮成一個同名的hello.sar文件,放到jboss-3.2.6\server\default\deploy目錄下。
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);
??? }
}?
注意:go方法里是三句。第一句比較長,它是根據jboss-service.xml文件中設置的MBean名稱,來取得此MBean在JBOSS中的實例。
2、在Mbean中加一個相應的調用Client.go的方法
在HelloWorldServiceMBean接口中加入一句:
void callGo();
在HelloWorldService類中加入現實方法:
??? public void callGo() {
??????? 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實例所反映的只是冰山一角而已。
六、參考資料:http://www.huihoo.com/java/jmx/jmx_base.html
?
總結
- 上一篇: Xquery 被设计用来查询 XML 数
- 下一篇: ESB 特性