JMX分析1-MBean的实现

JMX分析1-MBean的实现

      本文只是JDK7中JMX在本地,MBeanServer管理 MBeans 的默认实现的探索学习,没有涉及JMX Remote。
      JMX 使用了 Java Bean 模式来传递信息。一般说来,JMX 使用有名的 MBean,其内部包含了数据信息,这些信息可能是:应用程序配置信息、模块信息、系统信息、统计信息等。另外,MBean 也可以设立可读写的属性、直接操作某些函数甚至启动 MBean 可发送的 notification 等。MBean 包括 Standard,MXBean,Dynamic,Model,Open 等几种分类,其中最简单是标准 MBean 和 MXBean,而我们使用得最多的也是这两种。MXBean 主要是 java.lang.management使用较多,将在下一节中介绍。我们先了解其他一些重要的 MBean 的种类。

StandardMBean
      MXBean 规定了标准 MBean 也要实现一个接口,所有向外界公开的方法都要在这个接口中声明。否则,管理系统就不能从中获得相应的信息。此外,该接口的名字也有一定的规范:即在标准 MBean 类名之后加上“MBean”后缀。若 MBean 的类名叫做 MBeansName 的话,对应的接口就要叫做 MBeansNameMBean。
例子:
 1  package test.jmx;
 2 
 3  import javax.management.Notification;
 4  import javax.management.NotificationBroadcasterSupport;
 5 
 6 
 7  /**
 8   * 此标准MBean需实现XXXMBean这样名称的借口,XXX为这个类的名称,
 9   * 如果MBean需要消息事件的发送、监听等需要实现
10   *   @see  javax.management.NotificationBroadcaster,
11   * 或者继承 @see  javax.management.NotificationBroadcasterSupport
12 
13    */
14  public  class HelloWorld  extends NotificationBroadcasterSupport  implements HelloWorldMBean {
15      public String hello;
16     
17      private  long seq = 0l;
18 
19      public HelloWorld() {
20          this.hello = "Hello World! I am a Standard MBean";
21     }
22 
23      public HelloWorld(String hello) {
24          this.hello = hello;
25     }
26 
27      public String getHello() {
28          return hello;
29     }
30 
31     @Override
32      public Object getInstance() {
33          return  new Object();
34     }
35 
36      /*  
37       * 当执行message的时候,发送一个消息(事件)
38       * @see test.jmx.HelloWorldMBean#message(java.lang.String)
39        */
40     @Override
41      public String message(String ms) {
42         Notification notice =  new  Notification("type1", this,seq++," the message metheod is invoked,the argument ms: "+ms);
43         sendNotification(notice);
44          return " the message :   ";
45     }
46 
47     @Override
48      public  void setHello(String hello) {
49          this.hello = hello;
50     }
51 }
52 

 1 
 2  package test.jmx;
 3 
 4  public  interface HelloWorldMBean {
 5      public String getHello();
 6     
 7      public  void setHello(String hello);
 8     
 9      public Object getInstance();
10     
11      public String message(String ms);
12 
13 }
14 

测试 :
  1  package test.jmx;
  2 
  3  import java.util.Set;
  4 
  5  import javax.management.Attribute;
  6  import javax.management.MBeanOperationInfo;
  7  import javax.management.MBeanServer;
  8  import javax.management.MBeanServerFactory;
  9  import javax.management.Notification;
 10  import javax.management.NotificationListener;
 11  import javax.management.ObjectInstance;
 12  import javax.management.ObjectName;
 13  import javax.management.modelmbean.RequiredModelMBean;
 14 
 15  import org.junit.Test;
 16 
 17  public  class JmxTest {
 18     
 19      /**
 20       * 测试标准MBean
 21       * 需要被管理的方法、属性等在接口中定义好,创建一个类,继承此接口,然后实现时候方法, 
 22       * 这样,但注册到MBeanServer的时候,会自动管理其,接口中的各个属性、方法。
 23       *  @throws  Exception
 24        */
 25     @Test
 26      public  void test1StandardMBean()  throws Exception{
 27  //         MBeanServer ms = MBeanServerFactory.createMBeanServer("JMX2Test");
 28          MBeanServer ms = MBeanServerFactory.createMBeanServer();
 29         ObjectName name =  new ObjectName("Hello:type=myfirstMbean");
 30         
 31  //         ms.createMBean("HelloWorld", objectName);
 32          HelloWorld hello =  new HelloWorld(" yao yao , qie ke nao ");
 33         
 34          // MBean需要实现NotificationBroadcaster接口,支持各种事件的发送和处理
 35          hello.addNotificationListener( new NotificationListener() {
 36             @Override
 37              public  void handleNotification(Notification notification, Object handback) {
 38                 System.out.println(" access listen : "+notification);
 39             }
 40         }, null, null);
 41         
 42         ms.registerMBean(hello,name );
 43         
 44         String s1 = (String)ms.getAttribute(name, "Hello");
 45         System.out.println(" the init value : "+s1);
 46         
 47         ms.setAttribute(name,  new Attribute("Hello"," hi ,hi ,man "));
 48         String s2 = (String)ms.getAttribute(name, "Hello");
 49         System.out.println(" the init value : "+s2);
 50         
 51         ms.invoke(name, "message",  new Object[]{" i as message "},  new String[]{"java.lang.String"});
 52 
 53         ObjectName name2 =  new ObjectName("*:*");
 54         Set<ObjectInstance> set = ms.queryMBeans(name2,  null);
 55     }
 56     
 57      /**
 58       * 动态Mbean,需要实现DynamicMBean接口,并且任何需要,管理的方法、属性,都需要在接口的方法中,
 59       * 自己来实现,Mbeaninfo也需要自己设置,这样编程的工作量大,但是有很大的可控性。
 60       *  @throws  Exception
 61        */
 62     @Test
 63      public  void test2DynamicMBean()  throws Exception{
 64         HelloWorldDynamic dynamic =  new HelloWorldDynamic();
 65         
 66         MBeanServer ms = MBeanServerFactory.createMBeanServer();
 67          // 创建一个ObjectName
 68          ObjectName name =  new ObjectName("DynamicHello:type=dinamicMbean");
 69         
 70          // 注册动态MBean到MBeanServer服务上去
 71          ms.registerMBean(dynamic, name);
 72         
 73          // 得到属性值
 74          Object o = ms.getAttribute(name, "getInstance");
 75         String hello = (String)ms.getAttribute(name, "gh");
 76         MBeanOperationInfo operation = dynamic.getMBeanInfo().getOperations()[0];
 77         System.out.println(" attribute value of getInstance:"+o+"; attribute value of gh:"+hello);
 78         
 79          // 执行一个方法(操作)
 80          ms.invoke(name, operation.getName(),  nullnull);
 81     }
 82     
 83     @Test
 84      public  void test3RequiredModelMBean()  throws Exception{
 85         HelloWorldModelMBean hello =  new HelloWorldModelMBean();
 86         
 87         MBeanServer ms = MBeanServerFactory.createMBeanServer();
 88         RequiredModelMBean modelMbean = hello.createModelBean();
 89         ObjectName name =  new ObjectName("RequiredMBeanHello:type=ModelMbean");
 90          // 监听属性变化事件
 91          modelMbean.addAttributeChangeNotificationListener( new NotificationListener() {
 92             @Override
 93              public  void handleNotification(Notification notification, Object handback) {
 94                 System.out.println(" --Attribute已经改变-- ");
 95             }
 96         },  null, null);
 97         ms.registerMBean(modelMbean, name);
 98         
 99         ms.invoke(name, "setHello",  new Object[]{" aaa "}, new String[]{ "java.lang.String"});
100         String s = (String)ms.getAttribute(name, "hello");
101          // 出发Attribute改变事件
102          ms.setAttribute(name,  new Attribute("hello", "bbb"));
103         String s2 = (String)ms.getAttribute(name, "hello");
104         System.out.println(s);
105         System.out.println(s2);
106     }
107 }
108 
     
  • MBean注册
图:一个MBean被注册进MBeanServer的流程图


JmxMBeanServer在register一个MBean的时候,主要的步骤:
1. 查看MBean是否符合命名规则
2. 创建一个DynamicMBean,如果需要注册的是标准MBean,那么通过内省机制,得到标准的MBean各种元数据,这些数据封装组合到MBeanInfo中,接着创建StandardMBeanSupport(StandardMBeanSupport是DynamicMBean的子类) 。
3. JMX中按照ObjectName加上一次创建好的DynamicMBean,存入到Repository,Repository存的格式有点相当于Map的(key,value)。

  • MBeanServer的管理MBean分析
代码:MBeanServer.getAttribute(ObjectName name, String attribute)执行部分源码
 1  JmxMBeanServer:
 2        public Object getAttribute(ObjectName name, String attribute)
 3            throws MBeanException, AttributeNotFoundException,
 4                  InstanceNotFoundException, ReflectionException {
 5              // mbsInterceptor类型为DefaultMBeanServerInterceptor,也实现了MBeanServer接口,
 6               // JmxMBeanServer实现的MBeanServer接口的方法,基本都是由mbs代理执行的。
 7             return mbsInterceptor.getAttribute(cloneObjectName(name), attribute);
 8       }
 9   
10 DefaultMBeanServerInterceptor:
11       public Object getAttribute(ObjectName name, String attribute)
12           throws MBeanException, AttributeNotFoundException,
13                 InstanceNotFoundException, ReflectionException {       
14 
15           // 通过ObjectName(key)从Repository中得到注册过的MBean
16            final DynamicMBean instance = getMBean(name);
17 
18            // 得到Attribute的值
19             return instance.getAttribute(attribute);
20     }
21 StandardMBeanSupport:
22      public  final Object gtAttribute(String attribute)
23              throws AttributeNotFoundException,
24                    MBeanException,
25                    ReflectionException {
26          return perInterface.getAttribute(resource, attribute, getCookie());
27     }  
28 PerInterface:
29     Object getAttribute(Object resource, String attribute, Object cookie)
30              throws AttributeNotFoundException,
31                    MBeanException,
32                    ReflectionException {
33          // 得到Attribute属性的方法,也就是MBean接口中定义的getXXX()方法
34           final M cm = getters.get(attribute);
35          if (cm ==  null) {
36              final String msg;
37              if (setters.containsKey(attribute))
38                 msg = "Write-only attribute: " + attribute;
39              else
40                 msg = "No such attribute: " + attribute;
41              throw  new AttributeNotFoundException(msg);
42         }
43          // 在调用进去的话,就是通过反射调用cm方法,得到属性的值
44           return introspector.invokeM(cm, resource, (Object[])  null, cookie);
45     }

其他的比如setAttribute(...),和invoke(...)方法就是把上个getAttribute(...)替换相应方法名就可以了。
参照上面流程图和JDK中JMX的实现,可以看出JMX在内部实现中,对于标准MBean,也是转换成DynamicMBean(StandardMBeanSupport是DynamicMBean的子类)。

  • 相关的类说明
MBeanServerConnection、   MBeanServer、 JmxMBeanServer,DefaultMBeanServerInterceptor:
MBeanServerConnection提供一种连接到MBeanServer的途径,可以使本地的或者远程的。MBeanServer是作为一个本地的MBeanServerConnection,用于管理MBean的一个服务。主要提供创建、注册、移除MBean,MBean属性的获得和设置,MBean的操作(invoke),消息机制的支持,MBean的查询,MBean信息的展示。但是MBeanServer虽然目的是管理和对注册进来的MBean进行操作,但是没有方法是可以直接得到MBean实例的,只能通过MBeanServer对MBean进行操作。
图:MBeanServer结构

图:MBeanServer属性


PerInterface:
在JMX内省一个MBean的时候,代表了MBean实现的MBean接口的行为。其中的属性getters代表了MBean接口的getXXX方法,setters代表了MBean接口的setXXX方法,ops代表了MBean的其他方法。MBean接口中的getXXX()和setXXX()方法,在标准MBean中代表了一个属性的读和写,而其他的方法名,则代表着一个操作。MBeanServer调用的方式是不一样的,前者调用getAttbute(...)和setAttbute(...),而后者是调用invoke(...);
图:PerInterface结构


MBeanInfo、MBeanAttributeInfo、MBeanConstructorInfo、MBeanNotificationInfo、MBeanOperationInfo:
        这些类构成了MBean的所有信息。JMX利用Introspection机制分析MBean的数据,得到此MBean的元数据(i.e. 描述一个方法、属性的名称、类型、返回值等)。
MBeanAttributeInfo用于存放属性相关的元数据,MBeanConstructorInfo用于存放跟构造器相关的元数据,MBeanOperationInfo用于存放操作相关的元数据,MBeanNotificationInfo用于存放JMX消息(事件)相关的元数据。MBeanInfo就是存放所有的这些元数新,JMX管理系统如果想知道一个MBean能管理的属性或者能进行什么用的操作,那么都可以从MBeanInfo中获得信息。

图:MBeanInfo构成

NotificationBroadcasterSupport、NotificationListener、NotificationFilter、NotificationBroadcaster:
这些类就是提供MBean的消息机制。给予一个MBean发送消息,过滤消息、监听消息,执行消息等。一个MBean需要消息功能的话,就需要实现以后这些类。

图:消息机制的结构

Introspector、MBeanIntrospector:
JMX用这两个类进行内省,即通过他们能分析MBean的所有属性、方法,然后进行封装、转化、存储等,转化成我们需要的数据结构

MBeanRegistration :
用于一个MBean在注册前后,或者注销前后,做一些逻辑操作
图:MBeanRegistration结构图  


Dynamic、MBeanSupport、StandardMBeanSupport、MXBeanSupport:
即使MBean是标准形式的,但是JMX实现中,还是会生成一个动态的MBean,即StandardMBeanSupport,来封装标准MBean。
图:Dynamic、MBeanSupport、StandardMBeanSupport、MXBeanSupport关系图(列出部分属性、接口)

       
       总结:标准MBean按照一定编程规则(i.e. getXXX(),setXXX()),把需要管理的标准MBean的属性和操作,加入到接口的方法中,然后标准MBean实现这个接口,这样当标准MBean注册到MBeanServer中后,MBeanServer就可以管理此MBean了。标准MBean在于想要新增一个管理的属性或操作,都要先在接口中先新增一个方法,然后实现。

DynamicMBean
JMX管理的MBean除了标准MBean外,还可以是DynamicMBean。只要我们实现此接口,就可以被JMX Server管理。
例子:
 1  package test.jmx;
 2 
 3  import java.lang.reflect.Method;
 4 
 5  import javax.management.Attribute;
 6  import javax.management.AttributeList;
 7  import javax.management.AttributeNotFoundException;
 8  import javax.management.DynamicMBean;
 9  import javax.management.InvalidAttributeValueException;
10  import javax.management.MBeanAttributeInfo;
11  import javax.management.MBeanException;
12  import javax.management.MBeanInfo;
13  import javax.management.MBeanOperationInfo;
14  import javax.management.ReflectionException;
15 
16  public  class HelloWorldDynamic  implements DynamicMBean {
17      public String hello;
18     
19 
20      public HelloWorldDynamic() {
21          this.hello = "Hello World! I am a Dynamic MBean";
22     }
23 
24      public HelloWorldDynamic(String hello) {
25          this.hello = hello;
26     }
27 
28      public String getHello() {
29          return hello;
30     }
31 
32      public Object getInstance() {
33          return  new Object();
34     }
35 
36      public  void setHello(String hello) {
37          this.hello = hello;
38     }
39 
40     @Override
41      public Object getAttribute(String attribute)
42              throws AttributeNotFoundException, MBeanException,
43             ReflectionException {
44          // 设置getAttribute的执行逻辑
45           if("getInstance".equals(attribute)){
46              return getInstance();
47         }
48         
49          return  null;
50     }
51 
52     @Override
53      public AttributeList getAttributes(String[] attributes) {
54          //  TODO Auto-generated method stub
55           return  null;
56     }
57 
58     MBeanInfo info =  null;
59     @Override
60      public MBeanInfo getMBeanInfo()  {
61          try {
62             Class cls =  this.getClass();
63              //  用反射获得 "getHello" 属性的读方法
64               // DynamicMBean中,
65              Method readMethod = cls.getMethod("getHello",  new Class[0]);
66             MBeanAttributeInfo attribute =  new MBeanAttributeInfo("gh",
67                     " the first attribute ", readMethod,  null);
68              // 执行java类的method需要的一些元数据,由MBeanOperationInfo提供
69              MBeanOperationInfo operation =  new MBeanOperationInfo(
70                     " the first operation ", cls.getMethod("getInstance",  null));
71             info =  new MBeanInfo(cls.getName(), " this is a dynamic MBean ",
72                      new MBeanAttributeInfo[] { attribute },  null,
73                      new MBeanOperationInfo[] { operation },  null);
74         }  catch (Exception e) {
75             System.out.println(e);
76         }
77          return info;
78     }
79 
80     @Override
81      public Object invoke(String actionName, Object[] params, String[] signature)
82              throws MBeanException, ReflectionException {
83         System.out.println(" the HelloWorldDynamic's method invoke  ");
84          return  null;
85     }
86 
87     @Override
88      public  void setAttribute(Attribute attribute)
89              throws AttributeNotFoundException, InvalidAttributeValueException,
90             MBeanException, ReflectionException {
91         
92     }
93 
94     @Override
95      public AttributeList setAttributes(AttributeList attributes) {
96          return  null;
97     }
98 }
99 

测试此MBean请看JmxTest类中的test2DynamicMBean()。

       当实现一个DynamicMBean,我们需要写的代码量是非常多的,MBeanInfo的信息,需要自己编码,而且对于MBeanServer操作MBean的方法,也得自己重载实现。在动态MBean中,MBeanInfo里面的信息,主要用来展示的,具体的对DynamicMBean的操作是自己实现的。DynamicMBean的优点是对于逻辑控制是可以很灵活的。而不像标准MBean一样,所有的操作或属性需要在MBean接口中定义。在jdk中JMX实现DynamicMBean的流程是非常简单的,Jmx server对于DynamicMBean的操作也是非常简单的,相对于标准MBean,注册的时候少了内省的步骤;其他的操作跟标准MBean一样,只是对于getAttribute(...),setAttribute(...),invoke(...)等一些的操作都是需要自己来实现的。

ModelMBean
      然而,普通的动态 Bean通常缺乏一些管理系统所需要的支持:比如持久化MBean的状态、日志记录、缓存等等。如果让用户去一一实现这些功能确实是件枯燥无聊的工作。为了减轻用户的负担,JMX提供商都会提供不同的 ModelBean实现。其中有一个接口是 Java 规范中规定所有厂商必须实现的: javax.management.modelmbean.RequiredModelBean。通过配置Descriptor信息,我们可以定制这个ModelBean,指定哪些 MBean状态需要记入日志、如何记录以及是否缓存某些属性、缓存多久等等。对于Descriptor,在MBean中相当于附带的一些信息,这些信息在MBean实现中可以作为一种策略,以此增强MBean的功能。动态MBean以及标准MBean的MBeanInfo都已经包括了Descriptor,但是在逻辑实现中没用到此对象。在ModelMBean中,Descriptor作用非常大,持久化、日志、缓存等的策略等相关信息都是在Descriptor中定义的。开发人员可以增加相关属性到Descriptor中,来对应用功能进行扩展 
这里,我们以 RequiredModelBean 为例讨论 ModelBean。
例子:
  1  package test.jmx;
  2 
  3  import java.lang.reflect.Constructor;
  4 
  5  import javax.management.Descriptor;
  6  import javax.management.InstanceNotFoundException;
  7  import javax.management.MBeanException;
  8  import javax.management.MBeanOperationInfo;
  9  import javax.management.MBeanParameterInfo;
 10  import javax.management.RuntimeOperationsException;
 11  import javax.management.modelmbean.DescriptorSupport;
 12  import javax.management.modelmbean.InvalidTargetObjectTypeException;
 13  import javax.management.modelmbean.ModelMBeanAttributeInfo;
 14  import javax.management.modelmbean.ModelMBeanConstructorInfo;
 15  import javax.management.modelmbean.ModelMBeanInfo;
 16  import javax.management.modelmbean.ModelMBeanInfoSupport;
 17  import javax.management.modelmbean.ModelMBeanOperationInfo;
 18  import javax.management.modelmbean.RequiredModelMBean;
 19 
 20  public  class HelloWorldModelMBean  extends RequiredModelMBean {
 21     
 22      public HelloWorldModelMBean()  throws Exception{}
 23     
 24      public  static RequiredModelMBean createModelBean()
 25              throws RuntimeOperationsException, MBeanException,
 26             InstanceNotFoundException, InvalidTargetObjectTypeException {
 27          //  模型MBean信息
 28          ModelMBeanInfo info = buildModelMBeanInfo();
 29          //  模型MBean
 30          RequiredModelMBean modelMBean =  new RequiredModelMBean(info);
 31          // 目前只支持ObjectReference,将来可能会支持ObjectReference", "Handle", "IOR", "EJBHandle",
 32            //          or "RMIReference,
 33           // RMIReference从名字上可以看出,如果支持的话,那么以后就可以支持远程MBean引用
 34          modelMBean.setManagedResource( new HelloWorld(), "ObjectReference");
 35          return modelMBean;
 36     }
 37 
 38      protected  static ModelMBeanInfo buildModelMBeanInfo()  throws RuntimeOperationsException, MBeanException {  
 39          //  --  
 40           //  attributes  
 41           //  ------------------------------------------------------------------  
 42          ModelMBeanAttributeInfo[] attributes =  new ModelMBeanAttributeInfo[1];  
 43   
 44          //  设置属性
 45          Descriptor nameDesc =  new DescriptorSupport();  
 46         nameDesc.setField("name", "hello");
 47         nameDesc.setField("value", "----dfdf---");
 48         nameDesc.setField("displayName", "myname");  
 49         nameDesc.setField("setMethod", "setHello");  
 50         nameDesc.setField("getMethod", "getHello");  
 51         nameDesc.setField("descriptorType", "attribute"); 
 52         attributes[0] =  new ModelMBeanAttributeInfo("hello", "java.lang.String",  
 53                 "name say hello to",  truetruefalse, nameDesc);  
 54   
 55          //  --  
 56           //  operations  
 57           //  -------------------------------------------------------------------  
 58          ModelMBeanOperationInfo[] operations =  new ModelMBeanOperationInfo[2];  
 59         String className = HelloWorld. class.getName();  
 60   
 61          //  getName method  
 62          Descriptor getDesc =  new DescriptorSupport( new String[] {  
 63                 "name=getHello", "descriptorType=operation",  
 64                 "class=" + className, "role=operation" });  
 65         operations[0] =  new ModelMBeanOperationInfo("getHello", "get hello   ",  
 66                  nullnull, MBeanOperationInfo.ACTION,  getDesc);  
 67        
 68         Descriptor setDesc =  new DescriptorSupport( new String[] {  
 69                 "name=setHello", "descriptorType=operation", 
 70                 "class=" + className, "role=operation" });  
 71         operations[1] =  new ModelMBeanOperationInfo("setHello", "set hello   ",  
 72                  new MBeanParameterInfo[]{ new MBeanParameterInfo("a","java.lang.String"," a method's arg ")},
 73                  null, MBeanOperationInfo.ACTION,  setDesc);  
 74   
 75          //  constructors  
 76          ModelMBeanConstructorInfo[] constructors =  new ModelMBeanConstructorInfo[1];  
 77         Constructor<?>[] ctors = HelloWorld. class.getConstructors();  
 78   
 79   
 80         constructors[0] =  new ModelMBeanConstructorInfo("default constructor",  
 81                 ctors[0],  null);  
 82   
 83          //  ModelMBeanInfo  
 84          ModelMBeanInfo mmbeanInfo =  new ModelMBeanInfoSupport(className,  
 85                 "Simple implementation of model bean.", attributes,  null,  
 86                 operations /* null */nullnull);  
 87         
 88          // 设置一个Descriptor策略,这样RequiredModelMBean改变 Attribute值得时候会记录日志
 89           // 当然RequiredModelMBean还需要addAttributeChangeNotificationListener,注册一个监听器
 90          Descriptor globalDescriptor =  new DescriptorSupport( new String[]{
 91                 "name=HelloWorldModelMBean","displayName=globaldescriptor",
 92                 "descriptorType=mbean","log=T","logfile=hello.log"
 93         });
 94         mmbeanInfo.setMBeanDescriptor(globalDescriptor);
 95         
 96          return mmbeanInfo;  
 97     }  
 98 
 99 }
100 

使用ModelMBean中,有两步很重要,第一步设置动态MBean元数据:setModelMBeanInfo(...),MBeanServer会利用这些元数据管理MBean。第二步设置ModelMBean需要管理的对象:setManagerdResourece(...),第一步的元数据其实也就是被管理对象的元数据。这二步都是可以在运行时候动态的配置的,对于ModelMBeanInfo和Resource等相关信息可以在xml文件中进行配置。所以对于ModelMBean的实现,可以很好的利用xml等工具。

测试此MBean请看JmxTest类中的test3RequiredModelMBean()方法。  

代码:RequiredModelMBean.setAttribute(...)的执行分析
 1 JmxMBeanServer:
 2      public  void setAttribute(ObjectName name, Attribute attribute)
 3          throws InstanceNotFoundException, AttributeNotFoundException,
 4                InvalidAttributeValueException, MBeanException,
 5                ReflectionException  {
 6 
 7         mbsInterceptor.setAttribute(cloneObjectName(name),
 8                                     cloneAttribute(attribute));
 9     }
10 
11 DefaultMBeanServerInterceptor:
12      public  void setAttribute(ObjectName name, Attribute attribute)
13          throws InstanceNotFoundException, AttributeNotFoundException,
14                InvalidAttributeValueException, MBeanException,
15                ReflectionException  {
16  .
17          // 得到动态MBean
18          DynamicMBean instance = getMBean(name);
19         instance.setAttribute(attribute);
20  .
21     }
22 
23 RequiredModelMBean:
24      public  void setAttribute(Attribute attribute)
25          throws AttributeNotFoundException, InvalidAttributeValueException,
26                MBeanException, ReflectionException 
27  .
28         // modelMBeanInfo就是最开始创建的信息,得到一个AttributeInfo
29          ModelMBeanAttributeInfo attrInfo =
30             modelMBeanInfo.getAttribute(attrName);
31  .
32         Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
33         Descriptor attrDescr = attrInfo.getDescriptor();
34  .
35              // 得到set方法名
36              String attrSetMethod = (String)
37                 (attrDescr.getFieldValue("setMethod"));
38              // 得到get方法名
39              String attrGetMethod = (String)
40                 (attrDescr.getFieldValue("getMethod"));
41  .
42              // 更具必要参数,执行set方法。改变被管理资源的值
43                  invoke(attrSetMethod,
44                        ( new Object[] {attrValue}),
45                        ( new String[] {attrType}) );
46  .
47              // 发出Attribute改变的事件
48              sendAttributeChangeNotification(oldAttr,attribute);
49 
50     }
51      public  void sendAttributeChangeNotification(AttributeChangeNotification
52                                                 ntfyObj)
53          throws MBeanException, RuntimeOperationsException {
54  .
55          //  log notification if specified in descriptor
56          Descriptor ntfyDesc =
57             modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
58          // 这个就是在例子中设置的globalDescriptor
59          Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
60  .
61   if (mmbDesc !=  null) {
62              // 这些值都是我们设置在globalDescriptor的策略,也就是具体                               // 需要JMX的实现这需要各自实现的策略
63              logging = (String) mmbDesc.getFieldValue("log");
64              if ((logging !=  null) &&
65                 ( logging.equalsIgnoreCase("t") ||
66                   logging.equalsIgnoreCase("true") )) {
67                 logfile = (String) mmbDesc.getFieldValue("logfile");
68 
69                  if (logfile !=  null) {
70                      try {
71                         // 把相关信息写入日志
72                          writeToLog(logfile,"LogMsg: " +
73                            (( new Date(ntfyObj.getTimeStamp())).toString())+
74                            " " + ntfyObj.getType() + " " +
75                            ntfyObj.getMessage() +
76                            " Name = " + ntfyObj.getAttributeName() +
77                            " Old value = " + oldv +
78                            " New value = " + newv);
79                     }
80 
81     }
82 

在ModelMBean中一些重要的类:
ModelMBean:
实现了DynamicMBean,说明了ModelMBean也是动态MBean的一类,PersistentMBean持久化功能接口,还实现了消息机制。
图:ModelMBean的结构图


ModelMBeanInfo、ModelMBeanAttributeInfo、ModelMBeanConstructorInfo、ModelMBeanNotificationInfo、ModelMBeanOperationInfo:
这些类跟DynamicMBean里面介绍的类很相似,这里的ModelXXX都是XXX的子类。而且构成也跟他们的父类是一样的,子类只是扩展了一些信息。

RequiredModelMBean:
RequiredModelMBean实现了ModelMBean其实实现了DynamicMBean,其实它也是一个动态的MBean,规范中说明对于使用ModelMBean,第三方供应商都必须实现RequiredMoelMBean。 

参考:
http://www.ibm.com/developerworks/cn/java/j-lo-jse63/index.html( Java SE 6 新特性: JMX 与系统管理)
http://docs.oracle.com/javase/7/docs/technotes/guides/jmx/JMX_1_4_specification.pdf (JMX规范说明) 

你可能感兴趣的:(JMX分析1-MBean的实现)