JMX分析3-MXBean及OpenMBean

JMX分析3-MXBean及OpenMBean

       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接口

 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的实现类
 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基本类型)
 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服务
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          // 构造一个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中的方法前后,对参数或者返回值进行转化。
 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的实现。

参考:
http://tuhaitao.iteye.com/blog/807398 (JMX学习笔记(三)-MXBean  )

你可能感兴趣的:(JMX分析3-MXBean及OpenMBean)