通知

Spring の JMX 製品には、JMX 通知の包括的なサポートが含まれています。

通知用のリスナーの登録

Spring の JMX サポートにより、任意の数の NotificationListeners を任意の数の MBean に簡単に登録できます(これには、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 プロパティを介してリスナーとして登録された 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 に対して多数の個別のリスナーを登録する)必要がある場合は、代わりに(notificationListenerMappings プロパティよりも) notificationListeners リストプロパティを使用する必要があります。今回は、単一の MBean に対して NotificationListener を構成する代わりに、NotificationListenerBean インスタンスを構成します。NotificationListenerBean は、NotificationListener と ObjectName (または ObjectNames)をカプセル化し、それが MBeanServer で登録されます。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 通知モデル」というタイトルの JMX 仕様(1.2)のセクションを参照してください)

通知の公開

Spring は、Notifications を受信するための登録だけでなく、Notifications の公開もサポートします。

このセクションは、実際には MBeanExporter を介して MBean として公開された Spring 管理 Bean のみに関連しています。既存のユーザー定義 MBean は、通知の公開に標準の JMX API を使用する必要があります。

Spring の JMX 通知発行サポートの主要なインターフェースは、NotificationPublisher インターフェースです(org.springframework.jmx.export.notification パッケージで定義されています)。MBeanExporter インスタンスを介して MBean としてエクスポートされる Bean は、関連する NotificationPublisherAware インターフェースを実装して、NotificationPublisher インスタンスにアクセスできます。NotificationPublisherAware インターフェースは、NotificationPublisher のインスタンスを単純な setter メソッドを介して実装 Bean に提供し、Bean はそれを使用して Notifications を公開できます。

NotificationPublisher (Javadoc) インターフェースの javadoc に記載されているように、NotificationPublisher メカニズムを介してイベントを発行するマネージド Bean は、通知リスナーの状態管理を行いません。Spring の JMX サポートは、すべての JMX インフラストラクチャの課題を処理します。アプリケーション開発者として行う必要があるのは、NotificationPublisherAware インターフェースを実装し、提供された NotificationPublisher インスタンスを使用してイベントの発行を開始することだけです。NotificationPublisher は、管理対象 Bean が MBeanServer に登録された後に設定されることに注意してください。

NotificationPublisher インスタンスの使用は非常に簡単です。JMX Notification インスタンス(または適切な Notification サブクラスのインスタンス)を作成し、発行するイベントに関連するデータを通知に入力し、Notification を渡して NotificationPublisher インスタンスで sendNotification(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 サポートの優れた機能の 1 つです。ただし、クラスを Spring と JMX の両方に結合する価格タグが付いています。通常どおり、ここでのアドバイスは実用的です。NotificationPublisher が提供する機能が必要で、Spring と JMX の両方への結合を受け入れることができる場合は、そうしてください。