通知
Spring 的 JMX 功能包括对 JMX 通知的功能全面支持。
注册通知侦听器
Spring 的 JMX 支持使您可以轻松地将任意数量的NotificationListeners
与任意数量的 MBean 注册(这包括由 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(bean:name=testBean1
)广播 JMXNotification
时,通过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>
如果要为封闭的MBeanExporter
导出的所有 Bean 注册单个NotificationListener
实例,则可以使用特殊通配符(*
)作为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
时获得一个手动对象,并且我们还希望通过提供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>
(有关手动对象是什么以及NotificationFilter
是什么的完整讨论,请参阅 JMX 规范 (1.2) 中题为“JMX 通知模型”的部分。)
发布通知
Spring 不仅支持注册接收Notifications
,还支持发布Notifications
。
此部分实际上仅与作为 MBean 通过MBeanExporter 导出的 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
实例非常简单。您创建 JMXNotification
实例(或适当的Notification
子类的实例),使用与要发布的事件相关的数据填充通知,并在NotificationPublisher
实例上调用sendNotification(Notification)
,并将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 的耦合,那么就这样做。