当我们需要编写一个Java程序支持JMX时,可以参考该文章: 1. 整体的框架: 添加JMX的代码的整体框架比较简单 // 创建一个JMX的Bean Server实例 // create a JMX MBean Server server instance MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); 如果需要管理的对象叫多,建议可以先创建一个基础的MBean封装类,例如Mina框架中的org.apache.mina.integration.jmx.ObjectMBean类。对不同类型的管理类型继承ObjectMBean类,针对需要管理的对象创建一个合适的封装MBean,例如IoServiceMBean或者IoFilterMBean类。用这样的处理方式的好处是很明显的,就是方便分开管理。 将需要管理的实例取一个ObjectName,这个Name将成为该MBean实例的名字,这里需要遵循MBean的命名规范: ObjectName acceptorName = new ObjectName( acceptor.getClass().getPackage().getName() + ":type=acceptor,name=" + acceptor.getClass().getSimpleName()); 然后将该MBean注册到MBeanServer上 mBeanServer.registerMBean( acceptorMBean, acceptorName ); 这样,首先就完成了MBean的注册了。 2. 如何在MBean中添加属性、操作和通知 我们知道MBean中的对象可以分为属性、操作和通知三类,所有的信息都是通过MBeanInfo来加入MBean的。下面我们就来看看三种类型的对象是如果添加入MBean中的。 属性: 在MBeanInfo中添加属性信息时代码如下: List<ModelMBeanAttributeInfo> attributes = new ArrayList<ModelMBeanAttributeInfo>(); 通过在List中添加ModelMBeanAttributeInfo即可。那么问题来了,如何能够快速添加呢? 一般来说,我们在添加属性时,将属性分为两类,一类是该类MBean中默认添加的,一类是该类中个别的MBean实例需要特殊添加的。分别用方法: addAttributes(attributes, source); addExtraAttributes(attributes);(这个方法您看着写,反正搞一个ModelMBeanAttributeInfo扔进attributes就可以) 这里addAttributes有两个传入值,一个是attributes,也就是我们之前定义的属性List,另一个source是一个泛型,也就是传入的MBean。 对于传入的MBean,我们用 PropertyDescriptor[] pdescs = Introspector.getBeanInfo(type).getPropertyDescriptors();来获得该Bean中的属性描述。拿到Bean中的属性,那么下面干什么就由我们了.... 当然,以下的一些过滤方法还是值得效仿的: //对于只读属性就算了吧... if (pdesc.getReadMethod() == null) { continue; } // 对于管不了的就算了吧,比如这里是Class的属性 String attrName = pdesc.getName(); Class<?> attrType = pdesc.getPropertyType(); if (attrName.equals("class")) { continue; } // 对于没有读功能的就算了吧,至于什么是有读功能?那还不是你说啥就是啥:) if (!isReadable(type, attrName)) { continue; } // 看看这个属性能不能继续往下拆,比如Session啦,能的话爸爸就放了,只抓最下面的,谁让最下面的有价值呢:). if (isExpandable(type, attrName)) { expandAttribute(attributes, object, prefix, pdesc); continue; } 搞了一堆,然后呢,当然是装进List了 attributes.add(new ModelMBeanAttributeInfo(fqan, convertType(object.getClass(), attrName, attrType, writable).getName(), pdesc.getShortDescription(), true, writable, false)); 这里要特别说说converType方法,这个方法就是一个彻彻底底的类型大解密,怎么说呢,还是看代码吧。 private Class<?> convertType(Class<?> type, String attrName, Class<?> attrType, boolean writable) { if ((attrName != null) && ((attrType == Long.class) || (attrType == long.class))) { if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0) && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0) && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) { return Date.class; } } if (IoFilterChain.class.isAssignableFrom(attrType)) { return Map.class; } if (IoFilterChainBuilder.class.isAssignableFrom(attrType)) { return Map.class; } if (!writable) { if (Collection.class.isAssignableFrom(attrType) || Map.class.isAssignableFrom(attrType)) { if (List.class.isAssignableFrom(attrType)) { return List.class; } if (Set.class.isAssignableFrom(attrType)) { return Set.class; } if (Map.class.isAssignableFrom(attrType)) { return Map.class; } return Collection.class; } if (attrType.isPrimitive() || Date.class.isAssignableFrom(attrType) || Boolean.class.isAssignableFrom(attrType) || Character.class.isAssignableFrom(attrType) || Number.class.isAssignableFrom(attrType)) { if ((attrName == null) || !attrName.endsWith("InMillis") || !propertyDescriptors.containsKey(attrName.substring(0, attrName.length() - 8))) { return attrType; } } } return String.class; } 窃以为上面这个方法还是很值得拿来直接用的。 到这里,属性搞定! 2. 操作 在MBeanInfo中添加操作信息如下: List<ModelMBeanOperationInfo> operations = new ArrayList<ModelMBeanOperationInfo>(); 和属性类似,也是分为两类一类是该类MBean中默认添加的,一类是该类中个别的MBean实例需要特殊添加的。分别用方法: addOperations(operations, source); addExtraOperations(operations); 说到方法就没有属性那么复杂了,应该类本身就有获得方法的函数object.getClass().getMethods() 当然了,这里也有一些函数可以让大家来参考的: // 忽略Get和Set方法. if (mname.startsWith("is") || mname.startsWith("get") || mname.startsWith("set")) { continue; } // 忽略从Object那里继承过来的方法. if (mname.matches("(wait|notify|notifyAll|toString|equals|compareTo|hashCode|clone)")) { continue; } // 忽略一些不想当作方法的函数 if (!isOperation(mname, m.getParameterTypes())) { continue; } 和属性不太一样的地方,就是操作都有参数的,这点好理解吧 List<MBeanParameterInfo> signature = new ArrayList<MBeanParameterInfo>(); int i = 1; for (Class<?> paramType : m.getParameterTypes()) { String paramName = "p" + (i++); if (getPropertyEditor(source.getClass(), paramName, paramType) == null) { continue; } signature.add(new MBeanParameterInfo(paramName, convertType(null, null, paramType, true).getName(), paramName)); } 把操作的参数收集一下。 然后将操作注册到ModelMBeanOperationInfo中 Class<?> returnType = convertType(null, null, m.getReturnType(), false); operations.add(new ModelMBeanOperationInfo(m.getName(), m.getName(), signature .toArray(new MBeanParameterInfo[signature.size()]), returnType.getName(), ModelMBeanOperationInfo.ACTION)); 这里我们注意到了在impact这里用了 ModelMBeanOperationInfo.ACTION。那么如果是其它的impack怎么办?那么就只能请你重写了。。。 最后加上 operations.add(new ModelMBeanOperationInfo("unregisterMBean", "unregisterMBean", new MBeanParameterInfo[0], void.class.getName(), ModelMBeanOperationInfo.ACTION)); 总要有取消注册的方法吧?不过我觉得没有必要。。。 最后封装一下,返回一个给new ModelMBeanInfoSupport(className, description, attributes.toArray(new ModelMBeanAttributeInfo[attributes.size()]), constructors, operations.toArray(new ModelMBeanOperationInfo[operations.size()]), notifications); 3. Notification Mbean之间的通信是必不可少的,Notification就起到了在Mbean之间沟通桥梁的作用。JMX notification 由四部分组成: * Notification 这个相当于一个信息包,封装了需要传递的信息 * Notification broadcaster 这相当于一个广播器,把消息广播出去 * Notification listerner 这是一个监听器,用于监听广播出来的Notification消息 * Notification filter 这是一个过滤器,过滤掉不需要的Notification消息 Notification broadcaster不需要我们实现,JMX的内部已经有了。Notification filter一般也很少用。 常用接口 NotificationEmitter, 只要实现此接口,就可以发出Notification和订阅Notification. 类NotificationBroadcasterSupport则实现了NotificationEmitter. NotificationListener, 实现此接口的可以订阅JMX的Notification。 Notification, 消息本身。 Notification采用的是观察者模式,个人认为这在正式的应用中采用的机会不多,因为完全没有这样的必要。但是这里还是需要介绍一下的。 首先MBean需要继承NotificationBroadcasterSupport,用来提供广播服务。 在需要通知的方法中(比如值的改变),new一个Notification,比如AttributeChangeNotification,这个类是javax.management.Notification的子类,而javax.management.Notification这个类又是java.util.EventObject的子类,由此可以证实上边所说的,JMX通知机制使用了 观察者设计模式.javax.management.Notification是一个JMX的通知核心类,将来需要扩展或者其他JMX自带 的消息,均集成自此类.AttributeChangeNotification根据类名可知,是一个属性改变的通知,造方法参数如下: Object source, // 事件源,一直传递到java.util.EventObject的source long sequenceNumber, // 通知序号,标识每次通知的计数器 long timeStamp, // 通知发出的时间戳 String msg, // 通知发送的message String attributeName, // 被修改属性名 String attributeType, // 被修改属性类型 Object oldValue, // 被修改属性修改以前的值 Object newValue // 被修改属性修改以后的值 根据观察者模式,由事件与广播组成,所以这里继承了NotificationBroadcasterSupport,来提供广播机制,调用NotificationBroadcasterSupportr的sendNotification(notification) 发送广播, 广播会根据注册的观察者来对观察者进行逐一通知. 有广播,那么肯定有接收者啦。接收者需要继承NotificationListener接口,然后处理handleNotification(Notification n, Object handback)就可以了。继承了NotificationBroadcasterSupport是可以注册Listener的,用addNotificationListener(new HelloListener(), null, null); 就可以了 |
|
来自: 昵称20874412 > 《JMX》