?
Ce document utilise Manuel du site Web PHP chinois Libérer
Spring提供的JMX對(duì)JMX通知包含了全面的支持。
Spring的JMX支持使得用任意數(shù)量MBean注冊(cè)任意數(shù)量的 NotificationListeners
監(jiān)聽(tīng)器(包括由Spring的 MBeanExporter
輸出和其他機(jī)制注冊(cè)的MBean)都非常容易。
通過(guò)例子,考慮當(dāng)目標(biāo)MBean發(fā)生了變化都想得到通知(通過(guò) Notification
)的場(chǎng)景。
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>
上述配置就緒后,每當(dāng)目標(biāo)MBean(bean:name=testBean1
)廣播一個(gè)JMX Notification
時(shí),
通過(guò) notificationListenerMappings
屬性注冊(cè)的 ConsoleLoggingNotificationListener
都能得到通知。
ConsoleLoggingNotificationListener
就可以采取任何它認(rèn)為合適的行為來(lái)響應(yīng) Notification
。
你也可以直接使用Bean名作為輸出的Bean和監(jiān)聽(tīng)器直接的鏈接。
<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>
如果有人想為所有通過(guò) MBeanExporter
輸出的Bean注冊(cè)單個(gè) NotificationListener
實(shí)例,可以使用通配符'*'(沒(méi)有引號(hào))作為 notificationListenerMappings
屬性映射中一個(gè)實(shí)體的鍵值;如下:
<property name="notificationListenerMappings"> <map> <entry key="*"> <bean class="com.example.ConsoleLoggingNotificationListener"/> </entry> </map> </property>
如果想做相反的事情(也就是,為一個(gè)MBean注冊(cè)多個(gè)不同的監(jiān)聽(tīng)器),那么他就要使用 notificationListeners
列表屬性來(lái)替代(優(yōu)先于 notificationListenerMappings
屬性)。
這時(shí)就要配置多個(gè) NotificationListenerBean
實(shí)例,而不僅僅是一個(gè)了……
一個(gè) NotificationListenerBean
不但封裝了一個(gè)或者多個(gè) NotificationListener
和已注冊(cè)到一個(gè) MBeanServer
的 ObjectName
,它也封裝了許多其他屬性,例如一個(gè) NotificationFilter
和一個(gè)可以用于JMX高級(jí)通知場(chǎng)景的回傳對(duì)象。
當(dāng)使用多個(gè) NotificationListenerBean
實(shí)例時(shí),這個(gè)配置與前面展示的并沒(méi)有太大的不同。
<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>
上面例子等同與第一個(gè)通知示例。假設(shè)每次 Notification
發(fā)生時(shí),我們想得到一個(gè)回傳對(duì)象,
且想通過(guò)提供一個(gè) NotificationFilter
過(guò)濾出無(wú)關(guān)的 Notifications
。
至于什么是一個(gè)回傳對(duì)象,NotificationFilter
到底又是什么的全面的探討,請(qǐng)參考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> <!-- 實(shí)現(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不但提供了注冊(cè)接收通知的支持,也提供了對(duì)發(fā)布通知的支持。
要注意的是,本章節(jié)僅僅與通過(guò) MBeanExporter
暴露的,被Spring管理的Bean相關(guān)。
任何現(xiàn)存的,用戶(hù)定義的MBean應(yīng)當(dāng)使用標(biāo)準(zhǔn)JMX API來(lái)做通知發(fā)布。
Spring的JMX通知發(fā)布支持中的關(guān)鍵接口是 NotificationPublisher
(定義于 org.springframework.jmx.export.notification
包中)。
任意要通過(guò) MBeanExporter
實(shí)例輸出為MBean的Bean都可以實(shí)現(xiàn)
NotificationPublisherAware
接口來(lái)獲得對(duì) NotificationPublisher
實(shí)例的訪問(wèn)。
NotificationPublisherAware
僅僅提供通過(guò)一個(gè)簡(jiǎn)單的setter方法給實(shí)現(xiàn)了這個(gè)接口的Bean注入一個(gè)
NotificationPublisher
實(shí)例,那些Bean就因此可以發(fā)布 Notification
了。
就如 NotificationPublisher
類(lèi)的Javadoc描述的一樣,通過(guò) NotificationPublisher
機(jī)制發(fā)布事件的受控Bean是 不 需要對(duì)任何通知的監(jiān)聽(tīng)器或者其他諸如此類(lèi)的監(jiān)聽(tīng)器的狀態(tài)管理負(fù)責(zé)的。Spring的JMX支持將處理與JMX架構(gòu)相關(guān)的所有問(wèn)題。
作為一個(gè)應(yīng)用程序開(kāi)發(fā)者,他所需要做的只是實(shí)現(xiàn) NotificationPublisherAware
接口,然后利用注入的 NotificationPublisher
實(shí)例發(fā)布事件。要注意,受控Bean注冊(cè)到一個(gè) MBeanServer
后,NotificationPublisher
才被設(shè)置。
使用 NotificationPublisher
實(shí)例的方法很直觀,人們只要構(gòu)建一個(gè) Notification
實(shí)例(或者一個(gè)合適的 Notification
子類(lèi)的實(shí)例),接著填充與將要發(fā)布的事件相關(guān)的數(shù)據(jù)到通知里,然后傳入 Notification
,調(diào)用NotificationPublisher
實(shí)例的方法 sendNotification(Notification)
就可以了。
讓我們來(lái)看一個(gè)簡(jiǎn)單的例子,在這個(gè)場(chǎng)景里,輸出 JmxTestBean
實(shí)例在每次 add(int, int)
操作調(diào)用時(shí)都會(huì)發(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;
// 清晰起見(jiàn),忽略了其他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
接口和一套使之運(yùn)作的機(jī)制是Spring JMX支持的優(yōu)良特性之一。
它帶來(lái)的代價(jià)確實(shí)是使你的類(lèi)與Spring,JMX緊耦合了;與以往一樣,我們的建議也是很實(shí)際的……如果你需要 NotificationPublisher
提供的功能,并且接受與Spring,JMX的緊耦合,那么就行動(dòng)吧。