通知
Spring 的 JMX 產品提供了對 JMX 通知的全面支援。
註冊通知的 Listener
Spring 的 JMX 支援讓您可以輕鬆地向任意數量的 MBean 註冊任意數量的 NotificationListener
(包括 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
) 廣播 JMX Notification
時,都會通知透過 notificationListenerMappings
屬性註冊為 Listener 的 ConsoleLoggingNotificationListener
Bean。然後,ConsoleLoggingNotificationListener
Bean 可以針對 Notification
採取其認為適當的任何動作。
您也可以使用直接 Bean 名稱作為匯出的 Bean 和 Listener 之間的連結,如下列範例所示
<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
屬性 Map 中條目的鍵,如下列範例所示
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.example.ConsoleLoggingNotificationListener"/>
</entry>
</map>
</property>
如果您需要執行相反的操作(即,針對一個 MBean 註冊多個不同的 Listener),則必須改為使用 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
的支援。
本節實際上僅與透過 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 不負責通知 Listener 的狀態管理。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 的耦合,那就這樣做。