JMX之将Spring Bean 输出为带通知的MBean
Spring集成JMX是很简单的,这里通过注解发方式暴露JMX,有的时序我们需要监听JMX属性的改变,下面我们在Spring配置文件中配置监听器。
涉及到三个重要的annotation:@ManagedResource @ManagedAttribute 和 @ManagedOperation。
用途 Commons Attributes属性 JDK 5.0注解 属性/注解类型
将类的所有实例标识为JMX受控资源 | ManagedResource |
@ManagedResource |
Class 类 |
将方法标识为JMX操作 | ManagedOperation |
@ManagedOperation |
Method方法 |
将getter或者setter标识为部分JMX属性 | ManagedAttribute |
@ManagedAttribute |
Method (only getters and setters) 方法(仅getters和setters) |
定义操作参数说明 | ManagedOperationParameter |
@ManagedOperationParameter 和@ManagedOperationParameters
|
Method 方法 |
Parameter | Description | Applies to |
---|---|---|
ObjectName | Used by MetadataNamingStrategy to determine the ObjectName of a managed resource | ManagedResource |
description | Sets the friendly description of the resource, attribute or operation | ManagedResource, ManagedAttribute, ManagedOperation, ManagedOperationParameter |
currencyTimeLimit | Sets the value of the currencyTimeLimit descriptor field | ManagedResource, ManagedAttribute |
defaultValue | Sets the value of the defaultValue descriptor field | ManagedAttribute |
log | Sets the value of the log descriptor field | ManagedResource |
logFile | Sets the value of the logFile descriptor field | ManagedResource |
persistPolicy | Sets the value of the persistPolicy descriptor field | ManagedResource |
persistPeriod | Sets the value of the persistPeriod descriptor field | ManagedResource |
persistLocation | Sets the value of the persistLocation descriptor field | ManagedResource |
persistName | Sets the value of the persistName descriptor field | ManagedResource |
name | Sets the display name of an operation parameter | ManagedOperationParameter |
index | Sets the index of an operation parameter | ManagedOperationParameter |
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) 发送广播,广播会根据注册的观察者
来对观察者进行逐一通知.
/**
*
* @author Lenovo
* @version $Id: HelloMBean.java, v 0.1 2014年9月26日 下午4:28:17 Lenovo Exp $
*/
@Component
@ManagedResource(description = "hello demo", objectName = "bean:name=helloTest")
public class Hello extends NotificationBroadcasterSupport implements HelloMBean {
private final String name = "Reginald";
private int cacheSize = DEFAULT_CACHE_SIZE;
private static final int DEFAULT_CACHE_SIZE = 200;
private long sequenceNumber = 1;
/**
* @see com.cathy.demo.jmx.notifications.HiMBean#sayHello()
*/
@ManagedOperation(description = "say hello")
public void sayHello() {
System.out.println("Hello,Word");
}
/**
* @see com.cathy.demo.jmx.notifications.HiMBean#add(int, int)
*/
@ManagedOperation(description = "add")
@ManagedOperationParameters({
@ManagedOperationParameter(name = "x", description = "fist param"),
@ManagedOperationParameter(name = "y", description = "second param") })
public int add(int x, int y) {
return x + y;
}
/**
* 获取 name 属性,通过gatter 方法获取私有的成员属性,在这个例子中属性值是永远不会改变的;但是对于其他的属性可能在程序的运行期间进行
* 改变。然而一些属性代表统计数据,如,如运行时间,内存使用情况等是只读到 也就是不能通过接口改变的
* @see com.cathy.demo.jmx.notifications.HiMBean#getName()
*/
@ManagedAttribute
public String getName() {
return name;
}
/**
* 获取私有成员变量cacheSize 的值
* @see com.cathy.demo.jmx.notifications.HiMBean#getCacheSize()
*/
@ManagedAttribute
public int getCacheSize() {
return cacheSize;
}
/**
* 设置私有成员变量cacheSize 的值
* @see com.cathy.demo.jmx.notifications.HiMBean#setCacheSize(int)
*/
@ManagedAttribute
public void setCacheSize(int size) {
int oldSize = cacheSize;
System.out.println("Cache size now is " + oldSize);
/**
* 构建一个介绍属性改变的通知,
*/
Notification notification = new AttributeChangeNotification(this, sequenceNumber++,
System.currentTimeMillis(), "CacheSize changed", "cacheSize", "int", oldSize, size);
/**
* 发送通知
*/
sendNotification(notification);
cacheSize = size;
}
/**
* @see javax.management.NotificationBroadcasterSupport#getNotificationInfo()
*/
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
String[] types = new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE };
String name = AttributeChangeNotification.class.getName();
String description = "An attribute of this MBean has changed";
MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
return new MBeanNotificationInfo[] { info };
}
}
通知监听器:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
">
<aop:aspectj-autoproxy />
<context:annotation-config />
<context:component-scan base-package="com.cathy.demo.jmx.*" />
<bean id="jmxAttributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<!-- ObjectName命名策略 -->
<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource" />
</bean>
<bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter">
<!-- 指定messageInfo装配类 -->
<property name="assembler" ref="assembler" />
<!-- 指定ObjectName命名策略 -->
<property name="namingStrategy" ref="namingStrategy" />
<!-- 配置自动检测MBean -->
<property name="autodetect" value="true" />
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.cathy.demo.jmx.listener.ConfigNotificationListener" />
</entry>
</map>
</property>
</bean>
<bean id="fileReplicator" class="com.cathy.demo.jmx.annotation.FileReplicatorImpl" />
</beans>
/**
*
* @author zhangwei_david
* @version $Id: ConfigNotificationListener.java, v 0.1 2015年6月19日 下午4:37:09 zhangwei_david Exp $
*/
public class ConfigNotificationListener implements NotificationListener, NotificationFilter {
/** */
private static final long serialVersionUID = 1099818764372891903L;
/**
* @see javax.management.NotificationListener#handleNotification(javax.management.Notification, java.lang.Object)
*/
public void handleNotification(Notification notification, Object handback) {
log("SequenceNumber:" + notification.getSequenceNumber());
log("Type:" + notification.getType());
log("Message:" + notification.getMessage());
log("Source:" + notification.getSource());
log("TimeStamp:" + notification.getTimeStamp());
}
private void log(String message) {
System.out.println(message);
}
/**
* @see javax.management.NotificationFilter#isNotificationEnabled(javax.management.Notification)
*/
public boolean isNotificationEnabled(Notification notification) {
return true;
}
}
通过Jconsole控制台可以看到如下信息:
修改cacheSize 在eclipse的控制台可以看到如下日志:
log4j:WARN custom level class [# 输出DEBUG级别以上的日志] not found.
2015-06-21 13:42:55 [ main:0 ] - [ INFO ] @TestExecutionListeners is not present for class [class com.cathy.demo.jmx.AutoDetectJmxTest]: using defaults.
2015-06-21 13:42:56 [ main:137 ] - [ INFO ] Loading XML bean definitions from URL [file:/H:/Alipay.com/workspace4alipay/demo/target/classes/META-INF/spring/jmx-annotation-beans.xml]
2015-06-21 13:42:56 [ main:369 ] - [ INFO ] JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning
2015-06-21 13:42:56 [ main:421 ] - [ INFO ] Refreshing [email protected]f7ae5: startup date [Sun Jun 21 13:42:56 CST 2015]; root of context hierarchy
2015-06-21 13:42:56 [ main:580 ] - [ INFO ] Pre-instantiating singletons in org.s[email protected]40cd94: defining beans [org.springframework.aop.config.internalAutoProxyCreator,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,hello,jmxAttributeSource,assembler,namingStrategy,mbeanExporter,fileReplicator,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy
2015-06-21 13:42:56 [ main:693 ] - [ INFO ] Registering beans for JMX exposure on startup
2015-06-21 13:42:56 [ main:695 ] - [ INFO ] Bean with name 'hello' has been autodetected for JMX exposure
2015-06-21 13:42:56 [ main:705 ] - [ INFO ] Bean with name 'fileReplicator' has been autodetected for JMX exposure
2015-06-21 13:42:56 [ main:707 ] - [ INFO ] Located MBean 'hello': registering with JMX server as MBean [bean:name=helloTest]
2015-06-21 13:42:56 [ main:709 ] - [ INFO ] Located managed bean 'fileReplicator': registering with JMX server as MBean [com.cathy.demo.jmx.annotation:name=fileReplicator,type=FileReplicatorImpl]
Cache size now is 200
SequenceNumber:1
Type:jmx.attribute.change
Message:CacheSize changed
Source:bean:name=helloTest
TimeStamp:1434865528473