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
我們可以通過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的實現