MXBean跟標(biāo)準(zhǔn)MBean很像,標(biāo)準(zhǔn)MBean需要實現(xiàn)XXXXMBean這樣命名的接口,而MXBean則需要實現(xiàn)XXXXMXBean這樣命名的接口,也可以在接口上使用注解@MXBean,而不用強制使用XXXMXBean這樣的命名格式。但是MXBean有點在于它可以供任何的client,包括remote client訪問相關(guān)屬性和執(zhí)行相關(guān)操作。并且client不需要具有MXBean類(e.g. 在JConsole中,MBean類型也可以供remote client訪問,基本類型是可以展示的,但是一旦有復(fù)雜類型,那就不能顯示了)。為了滿足這種機制,JMX提供了一套Open type-Open value用于雙方交互。以使耦合度減少。VM的很多屬性都是通過MXBean的形式提供的。
例子:
代碼:ZooMXBean,MXBean接口 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的實現(xiàn)類 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,復(fù)雜的類型(不同于java基本類型) 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 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服務(wù)
28 cs.start();
29 30 System.out.println(" the mxbean server is start

");
31 }
32 }
33 代碼:Client端 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 //構(gòu)造一個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 //構(gòu)造一個CompositeData代表Tiger實例,用于addTiger(Tiger)的參數(shù)
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 //得到服務(wù)端Tiger的數(shù)量,新增了以后,應(yīng)該是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是其實現(xiàn)類;Tiger為自定義的一個Java類;Server為MBeanServer所在的服務(wù)端,可以使用JDK自帶的jconsole查看MXBean屬性;Client端,主要是驗證Tiger是如何轉(zhuǎn)化成Open Type并在Server-Clinet兩端操作的。
我們可以通過jconsole查看這個注冊的MXBean。
圖:ZooMXBean屬性
圖:Tiger屬性
Jconsole控制臺就是JMX兼容的監(jiān)視工具。它使用Java虛擬機的JMX機制來提供運行在Java平臺的應(yīng)用程序的各種信息。在上圖中我們可以看出屬性中Tiger值是CompositeDataSupport。為什么我們在ZooXMBean接口中定義的getTiger()方法,也即屬性Tiger的值為Tiger類的實例。但是jconsole平臺顯示的確是一個CompositeDataSupport呢。首先在jconsole這邊是沒有Tiger這個類的,即jconsole這端是不可能實例化出一個Tiger類型的實例的。但是CompositeDataSupport(父類:CompositeData)在JMX機制中是屬于Open Data。說到Open Data就得說下JMX 中的OpenMBean了,在OpenMBean中為了實現(xiàn)但新增一個'MBean',的時候Manager Application可以再運行時能發(fā)現(xiàn)這個新增'MBean',管理員能知道這個'MBean'的意思,和如何操作;并且不需要重新編譯。為了實現(xiàn)上述功能,JMX中有一套Open Type-Open Value集合。Manager Application與Agent之間的通信需要使用這套類型。正式應(yīng)該在Manager Application中也知道CompoisteData的結(jié)構(gòu),故能從中取得相應(yīng)的數(shù)據(jù),而不需要知道Tiger類。
表格1:Open type和Java Type對應(yīng)關(guān)系
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的數(shù)組形式,任意維度 |
Clinet與Server交互的流程: 1. Server端注冊一個MXBean的時候,JMX內(nèi)部會通過MXBeanMappingFactory.mappingForType(Type t, MXBeanMappingFactory f)方法建立起Java type 到Open Type的映射關(guān)系。
2. client客戶端執(zhí)行g(shù)etAttribute(...)或者invoke(...)操作的時候。需要傳遞一個Open Type的參數(shù)。想ZooMXBean.addTiger(Tiger)需要一個參數(shù),但是client端,是沒有Tiger類的,這時候就需要構(gòu)造一個CompositeType類型的值CompositeData傳遞給Server。
3. Server收到傳遞過來的Open Type參數(shù),通過MXBeanMapping.fromOpenValue(Object openValue)把Open Type類型的參數(shù)Open Value轉(zhuǎn)化到Java Type類型的Java Value實例(i.e. 如何參數(shù)為代表Tiger的CompositeData,那么MXBeanMapping就會通過這個CompositeData,構(gòu)造出一個真正的Tiger實例)。
4. Server端調(diào)用MXBean方法,得到一個Java Type的返回值。如果有返回值,那么就會通過MXBeanMapping.toOpenValue(Object javaValue)把Java Value轉(zhuǎn)換成Open Value。傳遞成client。
5. server-client端對于Open-Type的機制都是知道的。于是client就可以在得到的Open Value中得到想要的數(shù)據(jù)(不需要server端自定義類的字節(jié)碼,如Tiger)。
MXBeanMapping、MXBeanMappingFactory、DefaultMXBeanMappingFactory圖:MXBeanMappingFactory、MXBeanMapping結(jié)構(gòu)

MXBeanMapping用于Open Type-Java Type的映射,使它們可以相互轉(zhuǎn)化。MXBeanMappingFactory.mappingForType(Type t, MXBeanMappingFactory f)創(chuàng)建MXBeanMapping。DefaultMXBeanMappingFactory是MXBeanMappingFactory實現(xiàn)類,而MXBeanMapping的實現(xiàn)類是作為DefaultMXBeanMappingFactory內(nèi)部類。這些類是在JDK7中的sun包中的。不同的JDK可能實現(xiàn)不一樣,類名也可能不存在。
ConvertingMethod主要用于在執(zhí)行MXBean中的方法前后,對參數(shù)或者返回值進行轉(zhuǎn)化。
1 //MBserServer對MXBean的操作,最終都是執(zhí)行MXBean接口里面的方法,而ConvertingMethod就是對MXBean里面的方法,進行包裝。
//把調(diào)用者的Open Type參數(shù),轉(zhuǎn)化成Java Type;并且接口中方法的Java Type的返回值轉(zhuǎn)換成Open Type返回給調(diào)用者
2 ConvertingMethod:
3 //參數(shù)m其實就是MXBean接口中定義的方法,也就是需要MBeanServer管理的屬性和操作。這個方法用于對m進行相關(guān)的包裝、轉(zhuǎn)換。m中的參數(shù)、返回值都跟Open Type建立映射關(guān)系。
//通過源碼發(fā)現(xiàn),MXBean在被注冊的時候,會調(diào)用此方法。既MXBean中自定義的屬性、參數(shù)類型就是在這里更Open Type建立映射關(guān)系的
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,得到映射關(guān)系
19 returnMapping = mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
20 //得到m里面的所有參數(shù)類型
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的參數(shù)類型也映射到Open Type,得到映射關(guān)系
26 paramMappings[i] = mappingFactory.mappingForType(params[i], mappingFactory);
27 identity &= DefaultMXBeanMappingFactory.isIdentity(paramMappings[i]);
28 }
29 paramConversionIsIdentity = identity;
30 }
31
32 //通過MBeanServer來取MXBean的屬性或執(zhí)行操作,都會通過這個方法,然后到真正的Source Object執(zhí)行相應(yīng)的方法
33 private Object invokeWithOpenReturn(Object obj, Object[] params)
34 throws MBeanException, IllegalAccessException,
35 InvocationTargetException {
36 final Object[] javaParams;
37 try {
38 //把Open Type類型參數(shù)的值轉(zhuǎn)換到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執(zhí)行真正MXBean實例的方法
47 final Object javaReturn = method.invoke(obj, javaParams);
48 try {
49 //把需要返回給調(diào)用者的Java Type返回值,轉(zhuǎn)換成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映射關(guān)系,實現(xiàn)類型轉(zhuǎn)換
66 jparams[i] = paramMappings[i].fromOpenValue(params[i]);
67 return jparams;
68 }
69
總結(jié):JMX中對于MXBean的實現(xiàn)中可以看出,主要是定義了一套Open Type,使client端不需要知道Server端MXBean里面相關(guān)屬性類型的情況下,能得到需要的數(shù)據(jù),使程序更具更加靈活、兩端耦合段更低。為了得到這種便利性,我們自定義的MXBean和里面相關(guān)的自定義類型都需要按照一定規(guī)范來實現(xiàn)。其實JMX中的OpenMBean就是用這套Open Types使MBean具有"Open"特性的,具體可以參操MXBean的實現(xiàn)。
參考:http://tuhaitao.iteye.com/blog/807398 (JMX學(xué)習(xí)筆記(三)-MXBean )