二、JMX官方指導文檔 之 介紹MBeans

Lesson: Introducing MBeans

這節課介紹了JMX API的基本概念,即被管理的Bean或者MBeans。
一個MBean是一個被管理的Java對象,和JavaBean組件相似遵循一系列之後定義的JMX規範。一個MBean可以描述一個設備、應用或者其他被管理的資源。MBeans假定    一個被管理的接口包含下面的部分:
一些可讀或者可寫的屬性,或者他們兩者。
一些可被調用的操作
一個自描述
管理接口不改變MBean實例的聲明, 但是MBean可以在預定義的事件發生的時候發送通知。
JMX規範定義了五種類型的MBean:
  • Standard MBeans
  • Dynamic MBeans
  • Open MBeans
  • Model MBeans
  • MXBeans
下面的例子僅僅使用了最簡單的MBean,標準MBeans和MXBeans。


Standard MBeans

這節將介紹一個簡單的例子,標準MBean。
可以通過寫一個Java接口 SomethingMBean來定義一個標準的MBean,它的實現類是Something。接口中定義的每個方法要麼是MBean的屬性要麼是它的操作方法。默認每一個方法定義一個操作。屬性和操作是遵循確定設計模式的方法。一個標準的MBean由一個MBean接口和一個類組成。MBean接口列出了所有要暴露的屬性和方法。實現了這個接口的類提供了對資源功能的描述。
下面寫了一個標準MBean的例子和簡單的JMX代理來管理MBean。
MBean Interface
基礎的MBean接口:
package com.example; 
 
public interface HelloMBean { 
 
    public void sayHello(); 
    public int add(int x, int y); 
    
    public String getName(); 
     
    public int getCacheSize(); 
    public void setCacheSize(int size); 

約定MBean接口以實現它的類的名字加上MBean命名。這樣說的話,這個接口叫做HelloMBean。下節的Hello類實現了這個接口。
依據JMX規範,MBean接口包含可讀屬性、可寫屬性的名字和類型。根據這些操作可以調用應用中被管理的MBean。HelloMBean接口有兩個操作add()和sayHello()。
HelloMBean聲明瞭兩個屬性: Name是隻讀的字符串,CacheSzie是一個可讀可寫的整形。通過定義getter和setter來讓遠程的管理程序改變這個值。JMX規範定義:getter方法是一個有返回值的公共方法並且方法名以get開始。getter確保這個屬性值可以被遠程管理讀取,這個類型是返回對象的類型。setter是一個帶單個參數的公共方法,方法名以set開始。setter確保管理器可以賦一個新值給這個屬性,類型和屬性的類型一致。
這些操作和屬性的實現在接下來的章節。


MBean Implementation

實現了HelloMBean的Hello類如下:
package com.example; 
 
public class Hello ... 
    implements HelloMBean { 
    public void sayHello() { 
        System.out.println("hello, world"); 
    } 
     
    public int add(int x, int y) { 
        return x + y; 
    } 
     
    public String getName() { 
        return this.name; 
    }  
     
    public int getCacheSize() { 
        return this.cacheSize; 
    } 
     
    public synchronized void setCacheSize(int size) {
        ...
    
        this.cacheSize = size; 
        System.out.println("Cache size now " + this.cacheSize); 
    } 
    ...
     
    private final String name = "Reginald"; 
    private int cacheSize = DEFAULT_CACHE_SIZE; 
    private static final int  DEFAULT_CACHE_SIZE = 200; 
}
Hello類提供了定義在HelloMBean中的屬性和操作。sayHello()和add()操作非常簡單,但是你需要的真實的操作可能是簡單的或者複雜的。
Name屬性的get方法和CacheSize屬性的get、set方法也被定義完成。在這個例子中, Name屬性不會被改變。然而,這個屬性可能被運行的資源改變。例如,屬性可能代表統計數字,如:運行時間和內存使用情況。但是這裏Name僅僅是Reginald。
可以調用setCacheSize方法去改變CacheSize的200默認值。在實際的環境中,CacheSize可能還需要做一些其他的操作,例如:釋放對象和申請新的對象。這個例子打印了一些信息去表明緩存大小已經改變。然而可以使用複雜的操作來替代簡單的調用println()方法。
在下面的章節中你可以使用Hello MBean和定義的接口來管理這個資源。


Creating a JMX Agent to Manage a Resource

一旦資源已經使用MBeans描述完畢,就可以使用JMX代理管理這個資源。
JMX代理的核心組件是MBean server。MBean server是一個管理被註冊的MBean對象的服務器。JMX代理包括一些被管理的MBean夫婦。看關於MBeanServer的API文檔,然後看下面的實現:
Main類描述了一個基本的JMX代理:
package com.example; 
 
import java.lang.management.*; 
import javax.management.*; 
 
public class Main { 
 
    public static void main(String[] args) 
        throws Exception { 
     
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 
        ObjectName name = new ObjectName("com.example:type=Hello"); 
        Hello mbean = new Hello(); 
        mbs.registerMBean(mbean, name); 
          
        ...
     
        System.out.println("Waiting forever..."); 
        Thread.sleep(Long.MAX_VALUE); 
    } 



Main通過調用 java.lang.management.ManagementFactory的getPlatformMBeanServer() 創建實例化了一個平臺MBean server。如果MBean Server還沒有被平臺創建, getPlatformMBeanServer()會調用MBeanServerFactory.createMBeanServer()的方法去自動創建一個。Main中的MBean server實例叫做mbs.
接下來定義了要創建的MBean對象的對象名字。每一個JMX MBean必須有一個對象名字。這個對象名字是JMX類ObjectName的實例並且必須遵循JMX規範定義的一些語法。即對象名稱必須包含域和鍵屬性列表。Main中定義的對象名字的域是com.example(MBean存在的包名)。此外,鍵-值對聲明瞭這個對象是Hello類型。
一個叫做mBean的Hello對象被創建。這個叫做mBean的Hello對象然後被 MBeanServer.registerMBean()方法註冊進了mbs,它需要一個對象和一個對象名字參數。
當Hello MBean被註冊進MBean server,Main開始簡單的等待Hello的管理操作。在這個例子中,這些管理系統通過調用sayHello()和add()和屬性的getter setter來操作被管理的資源。


Running the Standard MBean Example

已經寫完了這個例子,你現在可以運行他了。在這個例子中,JConsole被用於連接這個MBean。
按下面的步驟運行:
1.打包你的JMX API例子成jmx_examples.zip,然後放到工作目錄。
2.解壓這個例子,使用終端窗口命令:
unzip jmx_examples.zip
3.在你的工作目錄編譯它:
javac com/example/*.java
4.如果你使用的是jdk1.6及以後版本,運行Main的應用:
java com.example.Main
否則使用:
java -Dcom.sun.management.jmxremote example.Main
5.在新的終端窗口中開啓JConsole
jconsole
新連接對話框打開後,然後連接。
6. 在新的連接對話框中選擇 com.example.Main 然後點擊連接。
關於當前平臺的概述被打開了
7. 選中MBeans標籤頁
這個面板展示了當前所有在MBean中註冊的MBeans
8. 在左側的面板中展開 com.example的MBean樹。
你可以看到Main中的Hello已經被註冊。如果你點擊Hello,你講看到相關的屬性和操作節點。
9. 展開Hello MBean的屬性節點
定義在Hello中的屬性被展示
10. 改變CacheSize的值爲150。
  在Main的命令行下你可以看到值已經被改變。
11. 展開Hello的操作節點
Hello MBean的sayHello()和add()操作也是可用的。
12. 點擊sayhello按鈕調用sayHello()
一個控制檯對話框將展示你已經調用成功。"hello, world"信息將在Main的終端窗口展示。
13. 提供兩個整形參數然後調用add()
這個結果將在JConsole對話框中展示
14. 關閉JConsole退出。


MXBeans

這一章節演示了一種特殊的MBean,叫做MXBeans。
MXBean是一種預定義了一些數據類型的MBean。使用這種方法可以讓你的MBean對所有的客戶端可用,包括遠程客戶端,即使這個客戶端沒有你MBean的訪問模型類。MXBeans提供了一個方便的方法把相關的值收集到一起而不用客戶端做一些特殊的配置。
和標準的MBeans一樣的方法,寫一個Java接口SomethingMXBean然後弄一個類實現它。但是不像標準的MBeans,MXBeans不需要這個類命名爲Something。接口中定義的每一個方法可能是MXBean類中的屬性或者操作。 @MXBean註解也可以用來標記Java接口,代替使用MXBean後綴命名。
MXBean存在於J2SE 5.0的java.lang.management包中。然而用戶也可以定義自己的MXBeans然後添加到java.lang.management中。
MXBeans背後的主要思想是類型,例如:java.lang.management.MemoryUsage 在這種情況下java.lang.management.MemoryMXBean被映射到一個標準類型的集合,也是javax.management.openmbean包下的開發類型。MXBean規範指定了嚴格的映射規則。然而,總的原則是簡單類型如整形和字符串類型保持不變,而複雜的類型例如MemoryUsage被映射成標準的類型CompositeDataSupport。
jmx_examples.zip中的例子包含了下面一些文件:
QueueSamplerMXBean接口
QueueSampler實現類實現了MXBean接口
QueueSample中的getQueueSample()方法返回了MXBean接口。
Main,啓動運行這個例子的入口
MXBean例子使用這些類完成了如下的操作:
定義了一個簡單的MXBean來管理 Queue<String>類型的資源
在MXBean中聲明瞭一個getter,getQueueSample,調用的時候返回了QueueSample的一個隊列快照還有下面的值:
快照的時間
隊列的大小
此時隊列的頭
在MBean server上面註冊MXBean。


MXBean Interface

下面的例子展示了 QueueSamplerMXBean接口:
package com.example; 
 
public interface QueueSamplerMXBean { 
    public QueueSample getQueueSample(); 
    public void clearQueue(); 

注意,你聲明瞭一個MXBean接口和標準的MBean接口一樣的方法。QueueSamplerMXBean接口聲明瞭一個getter,getQueueSample和一個clearQueue操作。


Defining MXBean Operations

QueueSampler 中聲明的操作如下面所示:
package com.example; 
 
import java.util.Date; 
import java.util.Queue; 
 
public class QueueSampler 
               implements QueueSamplerMXBean { 
    
   private Queue<String> queue; 
        
   public QueueSampler (Queue<String> queue) { 
       this.queue = queue; 
   } 
        
   public QueueSample getQueueSample() { 
       synchronized (queue) { 
           return new QueueSample(new Date(), 
                          queue.size(), queue.peek()); 
       } 
   } 
        
   public void clearQueue() { 
       synchronized (queue) { 
           queue.clear(); 
       } 
   } 

QueueSampler定義了MXBean接口中聲明的getQueueSample()和clearQueue() 方法。getQueueSample()返回了一個使用 java.util.Queue的peek()、size()和java.util.Date構造的QueueSample實例
Defining the Java Type Returned by the MXBean Interface
QueueSample類是這樣的:
package com.example; 
 
import java.beans.ConstructorProperties; 
import java.util.Date; 
 
public class QueueSample { 
    
   private final Date date; 
   private final int size; 
   private final String head; 
        
   @ConstructorProperties({"date", "size", "head"}) 
   public QueueSample(Date date, int size, 
                       String head) { 
       this.date = date; 
       this.size = size; 
       this.head = head; 
   } 
        
   public Date getDate() { 
       return date; 
   } 
        
   public int getSize() { 
       return size; 
   } 
        
   public String getHead() { 
       return head; 
   } 
}   


MXBean框架調用QueueSample的getter去轉換成一個複合數據(CompositeData)並且使用@ConstructorProperties註解從複合數據中重建一個QueueSample實例。


Creating and Registering the MXBean in the MBean Server

到目前爲止我們已經定義了一個MXBean接口和一個類實現了它。接下來MXBean必須被創建註冊到MBean server。這些動作在Main中執行。
package com.example; 
 
import java.lang.management.ManagementFactory; 
import java.util.Queue; 
import java.util.concurrent.ArrayBlockingQueue; 
import javax.management.MBeanServer; 
import javax.management.ObjectName; 
 
public class Main { 
 
   public static void main(String[] args) throws Exception { 
       MBeanServer mbs = 
           ManagementFactory.getPlatformMBeanServer(); 
               
       ...  
       ObjectName mxbeanName = new ObjectName("com.example:type=QueueSampler");
       
       Queue<String> queue = new ArrayBlockingQueue<String>(10);
       queue.add("Request-1");
       queue.add("Request-2");
       queue.add("Request-3");
       QueueSampler mxbean = new QueueSampler(queue);
       
       mbs.registerMBean(mxbean, mxbeanName);
                
       System.out.println("Waiting..."); 
       Thread.sleep(Long.MAX_VALUE); 
   } 

Main中主要乾了這些事:
獲取一個平臺MBean server。
創建一個QueueSampler對象名字。
爲QueueSampler創建一個Queue實例。
賦給QueueSampler。
註冊這個MXBean給MBean server,和標準MBean一樣的方法。


Running the MXBean Example

MXBean例子使用了標準MBeans章節的jmx_examples.zip。這個例子運行在jdk6及之後的平臺, 下面是運行步驟:
1. 如果你還沒有代碼,保存jmx_examples.zip到工作目錄。
2.在終端窗口中輸入以下命令:
unzip jmx_examples.zip
3.編譯work_dir下的類
javac com/example/*.java
4.啓動Main應用。
java com.example.Main
5.在同一臺電腦上開啓JConsole,這個新連接窗口顯示出來,你運行的JMX代理將會在列表中展示出來。
jconsole
6.在新連接窗口中選擇com.example.Main然後連接。
關於這個平臺的概述被展示出來了
7.點擊MBeans 標籤
這個面板展示了當前MBean server註冊的MBeans
8.展開左邊的com.example MBean樹。
你將看到Main創建、註冊的QueueSampler MBean。如果你點擊QueueSampler 你會看到它關聯的屬性和操作。
9.展開屬性節點
你會看到QueueSample 屬性出現在右邊的面板,有一個值:javax.management.openmbean.CompositeDataSupport.
10.雙擊CompositeDataSupport
你將看到QueueSample有值: date,head和size。因爲MXBean框架已經轉換QueueSample 實例爲CompositeData。如果你定義QueueSampler 作爲一個標準的MBean而不是MXBean,那麼JConsole將找不到QueueSample 類,因爲它不在類路徑中。如果QueueSampler 被註冊成標準MBean,那麼你在檢索QueueSample 屬性的時候會收到一個ClassNotFoundException。實際上JConsoel發現QueueSampler 演示瞭如何通過JMX客戶端如JConsole如何連接到JMX代理。
11.展開操作節點
調用clearQueue操作。
12.點擊clearQueue按鈕
方法調用成功的信息將會被展示
13.再一次展開屬性按鈕然後雙擊CompositeDataSupport 值
head和size值已經被重置
14.關閉JConsole



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章