通知
Infra JMX 产品包括对 JMX 通知的全面支持。
注册通知监听器
Infra JMX 支持使得向任意数量的 MBean 注册任意数量的 NotificationListeners 变得容易(这包括由 Infra 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="infra.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="infra.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="infra.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="infra.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 属性)。这一次,我们配置 NotificationListenerBean 实例,而不是为单个 MBean 配置 NotificationListener。NotificationListenerBean 封装了一个 NotificationListener 和它要在 MBeanServer 中注册的 ObjectName(或多个 ObjectName)。NotificationListenerBean 还封装了许多其他属性,例如 NotificationFilter 和可以在高级 JMX 通知场景中使用的任意回传对象。
使用 NotificationListenerBean 实例时的配置与前面介绍的并没有太大的不同,如下例所示:
<beans>
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="notificationListeners">
<list>
<bean class="infra.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="infra.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
前面的示例等同于第一个通知示例。那么,假设我们希望在每次发出 Notification 时都获得一个回传对象,并且我们还希望通过提供 NotificationFilter 来过滤掉无关的 Notifications。以下示例实现了这些目标:
<beans>
<bean id="exporter" class="infra.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="infra.jmx.export.NotificationListenerBean">
<constructor-arg ref="customerNotificationListener"/>
<property name="mappedObjectNames">
<list>
<!-- 处理来自两个不同 MBean 的通知 -->
<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>
<!-- 同时实现 NotificationListener 和 NotificationFilter 接口 -->
<bean id="customerNotificationListener" class="com.example.ConsoleLoggingNotificationListener"/>
<bean id="testBean1" class="infra.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
<bean id="testBean2" class="infra.jmx.JmxTestBean">
<property name="name" value="ANOTHER TEST"/>
<property name="age" value="200"/>
</bean>
</beans>
(有关什么是回传对象以及什么是 NotificationFilter 的完整讨论,请参阅 JMX 规范 (1.2) 中题为“JMX 通知模型”的部分。)
发布通知
Infra 不仅支持注册接收 Notifications,还支持发布 Notifications。
本节实际上仅与已通过 MBeanExporter 公开为 MBean 的 Infra 托管 Bean 相关。任何现有的用户定义的 MBean 都应使用标准 JMX API 进行通知发布。
|
Infra JMX 通知发布支持的关键接口是 NotificationPublisher 接口(定义在 infra.jmx.export.notification 包中)。任何将通过 MBeanExporter 实例导出为 MBean 的 Bean 都可以实现相关的 NotificationPublisherAware 接口,以获得对 NotificationPublisher 实例的访问权限。NotificationPublisherAware 接口通过一个简单的 setter 方法向实现 Bean 提供 NotificationPublisher 的实例,然后 Bean 可以使用该实例发布 Notifications。
如 NotificationPublisher 接口的 javadoc 中所述,通过 NotificationPublisher 机制发布事件的托管 Bean 不负责通知监听器的状态管理。Infra JMX 支持负责处理所有 JMX 基础设施问题。作为应用程序开发人员,您需要做的就是实现 NotificationPublisherAware 接口,并开始使用提供的 NotificationPublisher 实例发布事件。请注意,NotificationPublisher 是在托管 Bean 向 MBeanServer 注册后设置的。
使用 NotificationPublisher 实例非常简单。您创建一个 JMX Notification 实例(或适当的 Notification 子类的实例),使用与要发布的事件相关的数据填充通知,并在 NotificationPublisher 实例上调用 sendNotification(Notification),传入 Notification。
在以下示例中,JmxTestBean 的导出实例每当调用 add(int, int) 操作时都会发布 NotificationEvent:
package infra.jmx;
import infra.jmx.export.notification.NotificationPublisherAware;
import infra.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;
// 为清晰起见省略了其他 getter 和 setter
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 接口以及使其全部工作的机制是 Infra JMX 支持的较好功能之一。然而,它确实伴随着将您的类与 Infra 和 JMX 耦合的代价。一如既往,这里的建议是务实。如果您需要 NotificationPublisher 提供的功能,并且可以接受与 Infra 和 JMX 的耦合,那么就使用它。