|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
通知
Spring 的 JMX 功能包含对 JMX 通知的全面支持。
注册通知监听器
Spring 的 JMX 支持使得向任意数量的 MBean 注册任意数量的
NotificationListeners 变得非常简单(这包括由 Spring 的 MBeanExporter 导出的 MBean,以及通过其他机制注册的 MBean)。例如,考虑这样一种场景:每当目标 MBean 的某个属性发生变化时,用户都希望收到通知(通过 Notification)。以下示例会将通知输出到控制台:
package com.example;
import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
public class ConsoleLoggingNotificationListener
implements NotificationListener, NotificationFilter {
public void handleNotification(Notification notification, Object handback) {
System.out.println(notification);
System.out.println(handback);
}
public boolean isNotificationEnabled(Notification notification) {
return AttributeChangeNotification.class.isAssignableFrom(notification.getClass());
}
}
以下示例将ConsoleLoggingNotificationListener(在前面的示例中定义)添加到notificationListenerMappings中:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="bean:name=testBean1">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
通过上述配置,每当目标 MBean(Notification)广播一条 JMX bean:name=testBean1 时,通过 ConsoleLoggingNotificationListener 属性注册为监听器的 notificationListenerMappings bean 就会收到通知。随后,ConsoleLoggingNotificationListener bean 可以根据该 Notification 执行其认为合适的任何操作。
您也可以直接使用 bean 名称作为导出的 bean 与监听器之间的关联,如下例所示:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="testBean">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
如果你想为当前 NotificationListener 导出的所有 Bean 注册同一个 MBeanExporter 实例,可以在 * 属性映射中使用特殊的通配符(notificationListenerMappings)作为键,如下例所示:
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
如果您需要执行相反的操作(即,将多个不同的监听器注册到同一个 MBean),则必须使用 notificationListeners 列表属性(优先于 notificationListenerMappings 属性)。这次,我们不再为单个 MBean 配置一个 NotificationListener,而是配置多个 NotificationListenerBean 实例。NotificationListenerBean 封装了一个 NotificationListener 以及它要在 MBeanServer 中注册的 ObjectName(或 ObjectNames)。
NotificationListenerBean 还封装了其他一些属性,例如 NotificationFilter 和一个任意的手持返回对象,该对象可用于高级 JMX 通知场景。
使用 NotificationListenerBean 实例时的配置与前面介绍的内容并没有太大不同,如下例所示:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListeners">
<list>
<bean class="org.springframework.jmx.export.NotificationListenerBean">
<constructor-arg>
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</constructor-arg>
<property name="mappedObjectNames">
<list>
<value>bean:name=testBean1</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
前面的示例等同于第一个通知示例。现在假设我们希望每次触发 Notification 时都能获得一个回传对象(handback object),并且希望通过提供一个 Notifications 来过滤掉无关的 NotificationFilter。以下示例实现了这些目标:
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean1"/>
<entry key="bean:name=testBean2" value-ref="testBean2"/>
</map>
</property>
<property name="notificationListeners">
<list>
<bean class="org.springframework.jmx.export.NotificationListenerBean">
<constructor-arg ref="customerNotificationListener"/>
<property name="mappedObjectNames">
<list>
<!-- handles notifications from two distinct MBeans -->
<value>bean:name=testBean1</value>
<value>bean:name=testBean2</value>
</list>
</property>
<property name="handback">
<bean class="java.lang.String">
<constructor-arg value="This could be anything..."/>
</bean>
</property>
<property name="notificationFilter" ref="customerNotificationListener"/>
</bean>
</list>
</property>
</bean>
<!-- implements both the NotificationListener and NotificationFilter interfaces -->
<bean id="customerNotificationListener" class="com.example.ConsoleLoggingNotificationListener"/>
<bean id="testBean1" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
<bean id="testBean2" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="ANOTHER TEST"/>
<property name="age" value="200"/>
</bean>
</beans>
(关于回传对象(handback object)的完整讨论,以及NotificationFilter 的定义,请参见 JMX 规范(1.2 版)中题为“JMX 通知模型”的章节。)
发布通知
Spring 不仅支持注册以接收Notifications,还支持发布Notifications。
本节仅适用于通过 MBeanExporter 暴露为 MBean 的 Spring 管理的 Bean。任何已有的用户自定义 MBean 应使用标准的 JMX API 来发布通知。 |
Spring JMX 通知发布支持中的关键接口是 NotificationPublisher 接口(定义在 org.springframework.jmx.export.notification 包中)。任何将通过 MBeanExporter 实例导出为 MBean 的 Bean 都可以实现相关的 NotificationPublisherAware 接口,以获得对 NotificationPublisher 实例的访问权限。NotificationPublisherAware 接口通过一个简单的 setter 方法向实现该接口的 Bean 提供一个 NotificationPublisher 实例,该 Bean 随后即可使用此实例来发布 Notifications。
正如
NotificationPublisher
接口的 Javadoc 中所述,通过 NotificationPublisher 机制发布事件的管理 Bean 不负责通知监听器的状态管理。
Spring 的 JMX 支持负责处理所有 JMX 基础设施问题。
作为应用程序开发人员,您只需实现
NotificationPublisherAware 接口,并使用提供的 NotificationPublisher 实例开始发布事件。请注意,NotificationPublisher
是在管理 Bean 向 MBeanServer 注册之后设置的。
使用 NotificationPublisher 实例非常简单。您需要创建一个 JMX
Notification 实例(或某个合适的 Notification 子类的实例),
用与要发布事件相关的数据填充该通知,然后在 sendNotification(Notification) 实例上调用
NotificationPublisher 方法,并传入该 Notification。
在以下示例中,JmxTestBean 的导出实例每次调用 NotificationEvent 操作时都会发布一个 add(int, int):
package org.springframework.jmx;
import org.springframework.jmx.export.notification.NotificationPublisherAware;
import org.springframework.jmx.export.notification.NotificationPublisher;
import javax.management.Notification;
public class JmxTestBean implements IJmxTestBean, NotificationPublisherAware {
private String name;
private int age;
private boolean isSuperman;
private NotificationPublisher publisher;
// other getters and setters omitted for clarity
public int add(int x, int y) {
int answer = x + y;
this.publisher.sendNotification(new Notification("add", this, 0));
return answer;
}
public void dontExposeMe() {
throw new RuntimeException();
}
public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
this.publisher = notificationPublisher;
}
}
NotificationPublisher 接口以及使其正常工作的相关机制,是 Spring 对 JMX 支持中较为出色的功能之一。然而,这也带来了将您的类同时耦合到 Spring 和 JMX 的代价。一如既往,这里的建议是保持务实:如果您需要 NotificationPublisher 提供的功能,并且可以接受与 Spring 和 JMX 的耦合,那么就放心使用它。