通知
Spring 的 JMX 提供了對 JMX 通知的全面支援。
註冊通知監聽器
Spring 的 JMX 支援使得為任意數量的 MBeans 註冊任意數量的 NotificationListeners 變得很容易(這包括由 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>
有了上述配置,每當 JMX Notification 從目標 MBean (bean:name=testBean1) 廣播時,透過 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 和一個任意的 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>
(關於回傳物件以及 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。
正如 NotificationPublisher 介面的 javadoc 中所述,透過 NotificationPublisher 機制釋出事件的受管 Bean 不負責通知監聽器的狀態管理。Spring 的 JMX 支援負責處理所有 JMX 基礎設施問題。作為應用程式開發人員,您只需實現 NotificationPublisherAware 介面,並使用提供的 NotificationPublisher 例項開始釋出事件。請注意,NotificationPublisher 是在受管 Bean 註冊到 MBeanServer 之後設定的。
使用 NotificationPublisher 例項非常簡單。您建立一個 JMX Notification 例項(或適當的 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 的耦合,那麼就這樣做吧。