JMX 分析3-MXBean及OpenMBean

http://www.blogjava.net/heavensay/archive/2012/11/27/388202.html

       MXBean跟標準MBean很像,標準MBean需要實現XXXXMBean這樣命名的接口,而MXBean則需要實現XXXXMXBean這樣命名的接口,也可以在接口上使用註解@MXBean,而不用強制使用XXXMXBean這樣的命名格式。但是MXBean有點在於它可以供任何的client,包括remote client訪問相關屬性和執行相關操作。並且client不需要具有MXBean類(e.g. 在JConsole中,MBean類型也可以供remote client訪問,基本類型是可以展示的,但是一旦有複雜類型,那就不能顯示了)。爲了滿足這種機制,JMX提供了一套Open type-Open value用於雙方交互。以使耦合度減少。VM的很多屬性都是通過MXBean的形式提供的。
例子:
代碼:ZooMXBean,MXBean接口


Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 package test.jmx.mxbean.simple;
 2 
 3 public interface ZooMXBean {
 4     
 5     public Tiger getTiger();
 6     
 7     public void addTiger(Tiger tiger);
 8     
 9     public String getZooName();
10     
11     public int getTigerCount();
12 }
13 

代碼:ZooImpl,MXBean的實現類

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 package test.jmx.mxbean.simple;
 2 
 3 import java.util.ArrayList;
 4 import java.util.List;
 5 
 6 public class ZooImpl implements ZooMXBean {
 7 
 8     private String zooName = " China zoo";
 9     private static List<Tiger> list;
10     static {
11         //初始化一隻Tiger
12         Tiger tiger = new Tiger(" the first tiger");
13         list = new ArrayList<Tiger>();
14         list.add(tiger);
15     }
16     public void addTiger(Tiger tiger) {
17         list.add(tiger);
18     }
19 
20     public Tiger getTiger() {
21         return list.get(0);
22     }
23 
24     public int getTigerCount(){
25         return list.size();
26     }
27     
28     public String getZooName() {
29         return zooName;
30     }
31     
32     public String[] getAnimalNames(){
33         return new String[]{"bird","tiger","mouse"};
34     };
35 }
36 

代碼:Tiger,複雜的類型(不同於java基本類型)

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 package test.jmx.mxbean.simple;
 2 
 3 import java.beans.ConstructorProperties;
 4 
 5 
 6 public class Tiger {
 7     
 8     private String name;
 9     @ConstructorProperties({})
10     public Tiger(){
11         this.name = "the default constructor";
12     }
13     
14     @ConstructorProperties({"name"})
15     public Tiger(String name){
16         this.name = name;
17     }
18     
19     public String getName(){
20         return name;
21     }
22     
23     public String roar(){
24         return "@¥%%……";
25     }
26     
27     public void setName(String name){
28         this.name=name;
29     }
30     public String[] getFoodNames(){
31         return new String[]{"rabbit","sheep","pig"};
32     }
33 }
34 

代碼:Server

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 package test.jmx.mxbean.simple;
 2 
 3 import java.lang.management.ManagementFactory;
 4 import java.rmi.registry.LocateRegistry;
 5 
 6 import javax.management.MBeanServer;
 7 import javax.management.ObjectName;
 8 import javax.management.remote.JMXConnectorServer;
 9 import javax.management.remote.JMXConnectorServerFactory;
10 import javax.management.remote.JMXServiceURL;
11 
12 public class Server {
13     public static void main(String args[]) throws Exception{
14         
15 //        MBeanServer mbs = MBeanServerFactory.createMBeanServer();
16         MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
17         LocateRegistry.createRegistry(9999);
18         JMXServiceURL url = new JMXServiceURL(
19                 "service:jmx:rmi:///jndi/rmi://localhost:9999/server");
20         JMXConnectorServer cs = JMXConnectorServerFactory
21                 .newJMXConnectorServer(url, null, mbs);
22         
23         ZooMXBean mxbean = new ZooImpl();
24         ObjectName name = new ObjectName("ZooMXBean:type=MXBean");
25         //註冊ZooOpenMBean這個OpenMBean
26         mbs.registerMBean(mxbean, name);
27         //開起RMI服務
28         cs.start();
29         
30         System.out.println(" the mxbean server is start");
31     }
32 }
33 

代碼:Client端

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 
 2 package test.jmx.mxbean.simple;
 3 
 4 
 5 
 6 import javax.management.MBeanServerConnection;
 7 import javax.management.ObjectName;
 8 import javax.management.openmbean.ArrayType;
 9 import javax.management.openmbean.CompositeData;
10 import javax.management.openmbean.CompositeDataSupport;
11 import javax.management.openmbean.CompositeType;
12 import javax.management.openmbean.OpenType;
13 import javax.management.openmbean.SimpleType;
14 import javax.management.remote.JMXConnector;
15 import javax.management.remote.JMXConnectorFactory;
16 import javax.management.remote.JMXServiceURL;
17 
18 public class Client {
19     
20     public static void main(String[] args) throws Exception{
21 
22         //構造一個Rmi-Connector
23         JMXServiceURL url = new JMXServiceURL(
24                 "service:jmx:rmi:///jndi/rmi://localhost:9999/server");
25         JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
26         MBeanServerConnection msc = jmxc.getMBeanServerConnection();
27         
28         ObjectName name = new ObjectName("ZooMXBean:type=MXBean");
29         
30         Object tiger = msc.getAttribute(name, "Tiger");
31         if(tiger instanceof CompositeData){
32             System.out.println("返回的Tiger的類型爲CompositeData");
33             CompositeData data = (CompositeData)tiger;
34             String nm = (String)(data.get("name"));
35             String[] foods = (String[])(data.get("foodNames"));
36             System.out.println(" the tiger's name is :"+nm);
37             System.out.println(" the tiger's foods is :"+foods);
38         }
39         
40         Integer count1 = (Integer)msc.getAttribute(name, "TigerCount");
41         System.out.println(" the amount of tiger is:"+count1);
42         
43         //構造一個CompositeData代表Tiger實例,用於addTiger(Tiger)的參數
44         CompositeType ct2 = new CompositeType("test.jmx.mxbean.Tiger", " tiger---",
45                 new String[]{"name","foodNames"},
46                 new String[]{"-name-","-foods-"}, 
47                 new OpenType[]{SimpleType.STRING,new ArrayType(1,SimpleType.STRING)});
48         
49         CompositeData ct2V = new CompositeDataSupport(ct2,
50                 new String[]{"name","foodNames"},
51                    new Object[]{"the second tiger",new String[]{"food1","food2","food3"}}); 
52         
53         Object returnValue = msc.invoke(name, "addTiger", 
54                 new Object[]{ct2V},
55                 new String[]{CompositeData.class.getName()});
56         //得到服務端Tiger的數量,新增了以後,應該是2只
57         Integer count2 = (Integer)msc.getAttribute(name, "TigerCount");
58         System.out.println(" after invoke addTiger(),the amount of tiger is:"+count2);
59     }
60 }
61 
      上面例子中,我們自定義了ZooMXBean就是MXBean接口,ZooImpl是其實現類;Tiger爲自定義的一個Java類;Server爲MBeanServer所在的服務端,可以使用JDK自帶的jconsole查看MXBean屬性;Client端,主要是驗證Tiger是如何轉化成Open Type並在Server-Clinet兩端操作的。
我們可以通過jconsole查看這個註冊的MXBean。

圖:ZooMXBean屬性


圖:Tiger屬性


      Jconsole控制檯就是JMX兼容的監視工具。它使用Java虛擬機的JMX機制來提供運行在Java平臺的應用程序的各種信息。在上圖中我們可以看出屬性中Tiger值是CompositeDataSupport。爲什麼我們在ZooXMBean接口中定義的getTiger()方法,也即屬性Tiger的值爲Tiger類的實例。但是jconsole平臺顯示的確是一個CompositeDataSupport呢。首先在jconsole這邊是沒有Tiger這個類的,即jconsole這端是不可能實例化出一個Tiger類型的實例的。但是CompositeDataSupport(父類:CompositeData)在JMX機制中是屬於Open Data。說到Open Data就得說下JMX 中的OpenMBean了,在OpenMBean中爲了實現但新增一個'MBean',的時候Manager Application可以再運行時能發現這個新增'MBean',管理員能知道這個'MBean'的意思,和如何操作;並且不需要重新編譯。爲了實現上述功能,JMX中有一套Open Type-Open Value集合。Manager Application與Agent之間的通信需要使用這套類型。正式應該在Manager Application中也知道CompoisteData的結構,故能從中取得相應的數據,而不需要知道Tiger類。

表格1:Open type和Java Type對應關係

Java Type

Open Type

Open Value

java.lang.Void

SimpleType.Void

\

java.lang.Boolean

SimpleType.Boolean

java.lang.Boolean

java.lang.Character

SimpleType.Character

java.lang.Character

java.lang.Byte

SimpleType.Byte

java.lang.Byte

java.lang.Short

SimpleType.Short

java.lang.Short

java.lang.Integer

SimpleType.Integer

java.lang.Integer

java.lang.Long

SimpleType.Long

java.lang.Long

java.lang.Float

SimpleType.Float

java.lang.Float

java.lang.Double

SimpleType.Double

java.lang.Double

java.lang.String

SimpleType.String

java.lang.String

java.math.BigDecimal

SimpleType.BigDecimal

java.math.BigDecimal

java.math.BigInteger

SimpleType.BigInteger

java.math.BigInteger

java.util.Date

SimpleType.Date

java.util.Date

javax.management.ObjectName

javax.management.ObjectName

javax.management.ObjectName

javax.management.openmbean.CompositeType

javax.management.openmbean.CompositeType

CompositeData

javax.management.openmbean.TabularType

javax.management.openmbean.TabularType

TabularData

 

javax.management.openmbean.ArrayType

以上Open value的數組形式,任意維度


Clinet與Server交互的流程:
    1. Server端註冊一個MXBean的時候,JMX內部會通過MXBeanMappingFactory.mappingForType(Type t, MXBeanMappingFactory f)方法建立起Java type 到Open Type的映射關係。
    2. client客戶端執行getAttribute(...)或者invoke(...)操作的時候。需要傳遞一個Open Type的參數。想ZooMXBean.addTiger(Tiger)需要一個參數,但是client端,是沒有Tiger類的,這時候就需要構造一個CompositeType類型的值CompositeData傳遞給Server。
    3. Server收到傳遞過來的Open Type參數,通過MXBeanMapping.fromOpenValue(Object openValue)把Open Type類型的參數Open Value轉化到Java Type類型的Java Value實例(i.e. 如何參數爲代表Tiger的CompositeData,那麼MXBeanMapping就會通過這個CompositeData,構造出一個真正的Tiger實例)。
    4.  Server端調用MXBean方法,得到一個Java Type的返回值。如果有返回值,那麼就會通過MXBeanMapping.toOpenValue(Object javaValue)把Java Value轉換成Open Value。傳遞成client。
    5. server-client端對於Open-Type的機制都是知道的。於是client就可以在得到的Open Value中得到想要的數據(不需要server端自定義類的字節碼,如Tiger)。


  • 相關的類介紹:

MXBeanMapping、MXBeanMappingFactory、DefaultMXBeanMappingFactory
圖:MXBeanMappingFactory、MXBeanMapping結構



       MXBeanMapping用於Open Type-Java Type的映射,使它們可以相互轉化。MXBeanMappingFactory.mappingForType(Type t, MXBeanMappingFactory f)創建MXBeanMapping。DefaultMXBeanMappingFactory是MXBeanMappingFactory實現類,而MXBeanMapping的實現類是作爲DefaultMXBeanMappingFactory內部類。這些類是在JDK7中的sun包中的。不同的JDK可能實現不一樣,類名也可能不存在。 

 ConvertingMethod
主要用於在執行MXBean中的方法前後,對參數或者返回值進行轉化。

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> 1 //MBserServer對MXBean的操作,最終都是執行MXBean接口裏面的方法,而ConvertingMethod就是對MXBean裏面的方法,進行包裝。
   //把調用者的Open Type參數,轉化成Java Type;並且接口中方法的Java Type的返回值轉換成Open Type返回給調用者

 2 ConvertingMethod:
 3 //參數m其實就是MXBean接口中定義的方法,也就是需要MBeanServer管理的屬性和操作。這個方法用於對m進行相關的包裝、轉換。m中的參數、返回值都跟Open Type建立映射關係。
   //通過源碼發現,MXBean在被註冊的時候,會調用此方法。既MXBean中自定義的屬性、參數類型就是在這裏更Open Type建立映射關係的
 4     static ConvertingMethod from(Method m) {
 5         try {
 6             return new ConvertingMethod(m);
 7         } catch (OpenDataException ode) {
 8             final String msg = "Method " + m.getDeclaringClass().getName() +
 9                 "." + m.getName() + " has parameter or return type that " +
10                 "cannot be translated into an open type";
11             throw new IllegalArgumentException(msg, ode);
12         }
13     }
14 
15     private ConvertingMethod(Method m) throws OpenDataException {
16         this.method = m;
17         MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT;
18 //把m方法的返回值類型映射到Open Type,得到映射關係
19         returnMapping =                mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
20 //得到m裏面的所有參數類型
21         Type[] params = m.getGenericParameterTypes();
22         paramMappings = new MXBeanMapping[params.length];
23         boolean identity = true;
24         for (int i = 0; i < params.length; i++) {
25 //把m的參數類型也映射到Open Type,得到映射關係
26             paramMappings[i] = mappingFactory.mappingForType(params[i], mappingFactory);
27             identity &= DefaultMXBeanMappingFactory.isIdentity(paramMappings[i]);
28         }
29         paramConversionIsIdentity = identity;
30     }
31 
32 //通過MBeanServer來取MXBean的屬性或執行操作,都會通過這個方法,然後到真正的Source Object執行相應的方法
33     private Object invokeWithOpenReturn(Object obj, Object[] params)
34             throws MBeanException, IllegalAccessException,
35                    InvocationTargetException {
36         final Object[] javaParams;
37         try {
38 //把Open Type類型參數的值轉換到Java Type類型的值
39             javaParams = fromOpenParameters(params);
40         } catch (InvalidObjectException e) {
41             // probably can't happen
42             final String msg = methodName() + ": cannot convert parameters " +
43                 "from open values: " + e;
44             throw new MBeanException(e, msg);
45         }
46 //通過Source Object執行真正MXBean實例的方法
47         final Object javaReturn = method.invoke(obj, javaParams);
48         try {
49 //把需要返回給調用者的Java Type返回值,轉換成Open Type的值。
50             return returnMapping.toOpenValue(javaReturn);
51         } catch (OpenDataException e) {
52             // probably can't happen
53             final String msg = methodName() + ": cannot convert return " +
54                 "value to open value: " + e;
55             throw new MBeanException(e, msg);
56         }
57     }
58 
59     final Object[] fromOpenParameters(Object[] params)
60             throws InvalidObjectException {
61         if (paramConversionIsIdentity || params == null)
62             return params;
63         final Object[] jparams = new Object[params.length];
64         for (int i = 0; i < params.length; i++)
65 //通過Java Type - Open Type映射關係,實現類型轉換
66             jparams[i] = paramMappings[i].fromOpenValue(params[i]);
67         return jparams;
68     }
69 


總結:
JMX中對於MXBean的實現中可以看出,主要是定義了一套Open Type,使client端不需要知道Server端MXBean裏面相關屬性類型的情況下,能得到需要的數據,使程序更具更加靈活、兩端耦合段更低。爲了得到這種便利性,我們自定義的MXBean和裏面相關的自定義類型都需要按照一定規範來實現。其實JMX中的OpenMBean就是用這套Open Types使MBean具有"Open"特性的,具體可以參操MXBean的實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章