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 else40 msg = "No such attribute: " + attribute;
41 throw new AttributeNotFoundException(msg);
42 }
43 //在调用进去的话,就是通过反射调用cm方法,得到属性的值
44 return introspector.invokeM(cm, resource, (Object[])
null, cookie);
45 }
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在于想要新增一个管理的属性或操作,都要先在接口中先新增一个方法,然后实现。
DynamicMBeanJMX管理的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",
true,
true,
false, 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 null,
null, 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*/,
null,
null);
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 与系统管理)