?
Dokumen ini menggunakan Manual laman web PHP Cina Lepaskan
Spring提供的JMX對JMX通知包含了全面的支持。
Spring的JMX支持使得用任意數(shù)量MBean注冊任意數(shù)量的 NotificationListeners
監(jiān)聽器(包括由Spring的 MBeanExporter
輸出和其他機制注冊的MBean)都非常容易。
通過例子,考慮當目標MBean發(fā)生了變化都想得到通知(通過 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()); } }
<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
屬性注冊的 ConsoleLoggingNotificationListener
都能得到通知。
ConsoleLoggingNotificationListener
就可以采取任何它認為合適的行為來響應(yīng) Notification
。
你也可以直接使用Bean名作為輸出的Bean和監(jiān)聽器直接的鏈接。
<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注冊多個不同的監(jiān)聽器),那么他就要使用 notificationListeners
列表屬性來替代(優(yōu)先于 notificationListenerMappings
屬性)。
這時就要配置多個 NotificationListenerBean
實例,而不僅僅是一個了……
一個 NotificationListenerBean
不但封裝了一個或者多個 NotificationListener
和已注冊到一個 MBeanServer
的 ObjectName
,它也封裝了許多其他屬性,例如一個 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>
上面例子等同與第一個通知示例。假設(shè)每次 Notification
發(fā)生時,我們想得到一個回傳對象,
且想通過提供一個 NotificationFilter
過濾出無關(guān)的 Notifications
。
至于什么是一個回傳對象,NotificationFilter
到底又是什么的全面的探討,請參考JMX規(guī)范(1.2)'The JMX Notification Model'
章節(jié)。
<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> <!-- 實現(xiàn)了NotificationListener
和NotificationFilter
接口 --> <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>
Spring不但提供了注冊接收通知的支持,也提供了對發(fā)布通知的支持。
要注意的是,本章節(jié)僅僅與通過 MBeanExporter
暴露的,被Spring管理的Bean相關(guān)。
任何現(xiàn)存的,用戶定義的MBean應(yīng)當使用標準JMX API來做通知發(fā)布。
Spring的JMX通知發(fā)布支持中的關(guān)鍵接口是 NotificationPublisher
(定義于 org.springframework.jmx.export.notification
包中)。
任意要通過 MBeanExporter
實例輸出為MBean的Bean都可以實現(xiàn)
NotificationPublisherAware
接口來獲得對 NotificationPublisher
實例的訪問。
NotificationPublisherAware
僅僅提供通過一個簡單的setter方法給實現(xiàn)了這個接口的Bean注入一個
NotificationPublisher
實例,那些Bean就因此可以發(fā)布 Notification
了。
就如 NotificationPublisher
類的Javadoc描述的一樣,通過 NotificationPublisher
機制發(fā)布事件的受控Bean是 不 需要對任何通知的監(jiān)聽器或者其他諸如此類的監(jiān)聽器的狀態(tài)管理負責的。Spring的JMX支持將處理與JMX架構(gòu)相關(guān)的所有問題。
作為一個應(yīng)用程序開發(fā)者,他所需要做的只是實現(xiàn) NotificationPublisherAware
接口,然后利用注入的 NotificationPublisher
實例發(fā)布事件。要注意,受控Bean注冊到一個 MBeanServer
后,NotificationPublisher
才被設(shè)置。
使用 NotificationPublisher
實例的方法很直觀,人們只要構(gòu)建一個 Notification
實例(或者一個合適的 Notification
子類的實例),接著填充與將要發(fā)布的事件相關(guān)的數(shù)據(jù)到通知里,然后傳入 Notification
,調(diào)用NotificationPublisher
實例的方法 sendNotification(Notification)
就可以了。
讓我們來看一個簡單的例子,在這個場景里,輸出 JmxTestBean
實例在每次 add(int, int)
操作調(diào)用時都會發(fā)布 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;
// 清晰起見,忽略了其他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
接口和一套使之運作的機制是Spring JMX支持的優(yōu)良特性之一。
它帶來的代價確實是使你的類與Spring,JMX緊耦合了;與以往一樣,我們的建議也是很實際的……如果你需要 NotificationPublisher
提供的功能,并且接受與Spring,JMX的緊耦合,那么就行動吧。