|
对于最新的稳定版本,请使用 Spring Framework 7.0.6! |
通知
Spring的JMX功能包括对JMX通知的全面支持。
注册通知监听器
Spring的JMX支持使注册任意数量的
NotificationListeners 与任意数量的MBeans(这包括由Spring的MBeanExporter导出的MBeans以及通过其他机制注册的MBeans)变得非常容易。例如,考虑这样一个场景:每次目标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(bean:name=testBean1)广播一个JMX Notification时,通过notificationListenerMappings属性注册为监听器的ConsoleLoggingNotificationListener 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以及它要注册到的ObjectName(或ObjectNames)的MBeanServer。NotificationListenerBean还封装了其他一些属性,例如NotificationFilter和任意的handback对象,该对象可以在高级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时都获得一个回调对象,并且希望通过提供NotificationFilter来过滤掉多余的Notifications。下面的示例实现了这些目标:
<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对象的完整讨论,以及实际上有关NotificationFilter的讨论,请参阅JMX规范(1.2)中名为“JMX通知模型”的章节。)
发布通知
Spring 不仅支持注册以接收 Notifications,还支持发布 Notifications。
本节仅适用于通过 MBeanExporter 暴露为 MBeans 的 Spring 管理的 Bean。任何现有的用户定义的 MBeans 应该使用标准的 JMX API 进行通知发布。 |
Spring的JMX通知发布支持中的关键接口是
NotificationPublisher接口(在
org.springframework.jmx.export.notification包中定义)。任何要通过
MBeanExporter实例导出为MBean的bean都可以实现相关的
NotificationPublisherAware接口,以获得对
NotificationPublisher
实例的访问权限。该
NotificationPublisherAware接口通过一个简单的setter方法向实现该接口的bean提供一个
NotificationPublisher的实例,该bean随后可以发布
Notifications。
如 javadoc 中所述,
NotificationPublisher
接口,通过 NotificationPublisher
机制发布事件的托管 Bean 不负责通知监听器的状态管理。
Spring 的 JMX 支持会处理所有 JMX 基础设施问题。
作为应用程序开发人员,您需要实现
NotificationPublisherAware 接口并通过使用提供的
NotificationPublisher 实例开始发布事件。请注意,
NotificationPublisher
是在托管 Bean 注册到 MBeanServer 之后设置的。
使用 NotificationPublisher 实例非常简单。您需要创建一个 JMX
Notification 实例(或适当的 Notification 子类的实例),
将与要发布的事件相关的数据填充到通知中,
然后在 sendNotification(Notification) 上调用
NotificationPublisher 实例,并传入 Notification。
在下面的示例中,导出的 JmxTestBean 实例在每次调用 add(int, int) 操作时发布一个 NotificationEvent:
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 的耦合,那么就可以这么做。