通知
Spring 的 JMX 提供全面的 JMX 通知支援。
為通知註冊監聽器
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>
有了前面的配置,每當 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
和可以在高階 JMX 通知場景中使用的任意回執物件(handback object)。
使用 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 不負責通知監聽器的狀態管理。Spring 的 JMX 支援負責處理所有 JMX 基礎設施問題。作為應用開發者,您所需要做的就是實現 NotificationPublisherAware
介面,並開始使用提供的 NotificationPublisher
例項釋出事件。請注意,NotificationPublisher
是在託管 bean 註冊到 MBeanServer
之後設定的。
使用 NotificationPublisher
例項非常簡單。您建立一個 JMX Notification
例項(或適當的 Notification
子類的例項),用與要釋出的事件相關的資料填充通知,並在 NotificationPublisher
例項上呼叫 sendNotification(Notification)
,傳入 Notification
。
在以下示例中,每當呼叫 add(int, int)
操作時,匯出的 JmxTestBean
例項都會發佈一個 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 的耦合,那麼就這樣做。