Bean を JMX にエクスポートする

Spring の JMX フレームワークのコアクラスは MBeanExporter です。このクラスは、Spring Bean を取得し、JMX MBeanServer に登録します。例: 次のクラスを検討します。

package org.springframework.jmx;

public class JmxTestBean implements IJmxTestBean {

	private String name;
	private int age;
	private boolean isSuperman;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public int add(int x, int y) {
		return x + y;
	}

	public void dontExposeMe() {
		throw new RuntimeException();
	}
}

この Bean のプロパティとメソッドを MBean の属性と操作として公開するには、次の例に示すように、構成ファイルで MBeanExporter クラスのインスタンスを構成し、Bean を渡すことができます。

<beans>
	<!-- this bean must not be lazily initialized if the exporting is to happen -->
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean1" value-ref="testBean"/>
			</map>
		</property>
	</bean>
	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>
</beans>

上記の構成スニペットからの適切な Bean 定義は、exporter Bean です。beans プロパティは、どの Bean を JMX MBeanServer にエクスポートする必要があるかを MBeanExporter に正確に伝えます。デフォルト構成では、beansMap の各エントリのキーは、対応するエントリ値によって参照される Bean の ObjectName として使用されます。Bean の ObjectName インスタンスの制御に従って、この動作を変更できます。

この構成では、testBean Bean は ObjectNamebean:name=testBean1 で MBean として公開されます。デフォルトでは、Bean のすべての public プロパティは属性として公開され、すべての public メソッド(Object クラスから継承されたものを除く)は操作として公開されます。

MBeanExporter は Lifecycle Bean です(起動とシャットダウンのコールバックを参照)。デフォルトでは、MBean はアプリケーションのライフサイクル中にできるだけ遅くエクスポートされます。autoStartup フラグを設定することにより、エクスポートが行われる phase を構成したり、自動登録を無効にしたりできます。

MBeanServer の作成

前のセクションに示されている構成は、1 つ(および 1 つ)の MBeanServer がすでに実行されている環境でアプリケーションが実行されていることを前提としています。この場合、Spring は実行中の MBeanServer を見つけて、そのサーバー(存在する場合)に Bean を登録しようとします。この動作は、アプリケーションが独自の MBeanServer を持つコンテナー(Tomcat や IBM WebSphere など)内で実行される場合に役立ちます。

ただし、このアプローチは、スタンドアロン環境や、MBeanServer を提供しないコンテナー内で実行する場合には役に立ちません。これに対処するには、org.springframework.jmx.support.MBeanServerFactoryBean クラスのインスタンスを構成に追加して、MBeanServer インスタンスを宣言的に作成できます。次の例に示すように、MBeanExporter インスタンスの server プロパティの値を MBeanServerFactoryBean によって返される MBeanServer 値に設定することにより、特定の MBeanServer が使用されるようにすることもできます。

<beans>

	<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>

	<!--
	this bean needs to be eagerly pre-instantiated in order for the exporting to occur;
	this means that it must not be marked as lazily initialized
	-->
	<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="server" ref="mbeanServer"/>
	</bean>

	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

</beans>

上記の例では、MBeanServer のインスタンスが MBeanServerFactoryBean によって作成され、server プロパティを介して MBeanExporter に提供されます。独自の MBeanServer インスタンスを提供する場合、MBeanExporter は実行中の MBeanServer を見つけようとせず、提供された MBeanServer インスタンスを使用します。これが正しく機能するには、クラスパスに JMX 実装が必要です。

既存の MBeanServer の再利用

サーバーが指定されていない場合、MBeanExporter は実行中の MBeanServer を自動的に検出しようとします。これは、MBeanServer インスタンスが 1 つだけ使用されるほとんどの環境で機能します。ただし、複数のインスタンスが存在する場合、エクスポータは間違ったサーバーを選択する可能性があります。このような場合、次の例に示すように、MBeanServeragentId を使用して、使用するインスタンスを指定する必要があります。

<beans>
	<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
		<!-- indicate to first look for a server -->
		<property name="locateExistingServerIfPossible" value="true"/>
		<!-- search for the MBeanServer instance with the given agentId -->
		<property name="agentId" value="MBeanServer_instance_agentId>"/>
	</bean>
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="server" ref="mbeanServer"/>
		...
	</bean>
</beans>

既存の MBeanServer にルックアップメソッドを通じて取得される動的な (または未知の) agentId があるプラットフォームまたはケースの場合は、次の例に示すように、Factory-method を使用する必要があります。

<beans>
	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="server">
			<!-- Custom MBeanServerLocator -->
			<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
		</property>
	</bean>

	<!-- other beans here -->

</beans>

遅延初期化された MBean

遅延初期化用に構成された MBeanExporter を使用して Bean を構成する場合、MBeanExporter はこの契約を破らず、Bean のインスタンス化を回避します。代わりに、プロキシを MBeanServer に登録し、プロキシで最初の呼び出しが発生するまでコンテナーから Bean の取得を延期します。

これは、MBeanExporter が生成されたオブジェクトを定期的にイントロスペクトし、効果的に FactoryBean.getObject() をトリガーする FactoryBean 解決にも影響します。これを回避するには、対応する Bean 定義を Lazy-init としてマークします。

MBean の自動登録

MBeanExporter を介してエクスポートされ、すでに有効な MBean である Bean は、Spring からの介入なしに MBeanServer にそのまま登録されます。次の例に示すように、autodetect プロパティを true に設定することにより、MBean を MBeanExporter によって自動的に検出させることができます。

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
	<property name="autodetect" value="true"/>
</bean>

<bean name="spring:mbean=true" class="org.springframework.jmx.export.TestDynamicMBean"/>

上記の例では、spring:mbean=true と呼ばれる Bean はすでに有効な JMX MBean であり、Spring によって自動的に登録されます。デフォルトでは、JMX 登録用に自動検出される Bean の Bean 名は ObjectName として使用されます。Bean の ObjectName インスタンスの制御で詳述されているように、この動作をオーバーライドできます。

登録動作の制御

Spring MBeanExporter が ObjectNamebean:name=testBean1 を使用して MBean を MBeanServer に登録しようとするシナリオを考えてみます。MBean インスタンスが同じ ObjectName ですでに登録されている場合、デフォルトの動作は失敗します(そして InstanceAlreadyExistsException をスローします)。

MBean が MBeanServer に登録されたときに何が起こるかを正確に制御できます。Spring の JMX サポートでは、MBean が同じ ObjectName にすでに登録されていることが登録プロセスで検出された場合、3 つの異なる登録動作により登録動作を制御できます。次の表は、これらの登録動作をまとめたものです。

表 1: 登録動作
登録動作 説明

FAIL_ON_EXISTING

これがデフォルトの登録動作です。MBean インスタンスが同じ ObjectName にすでに登録されている場合、登録されている MBean は登録されず、InstanceAlreadyExistsException がスローされます。既存の MBean は影響を受けません。

IGNORE_EXISTING

MBean インスタンスが同じ ObjectName にすでに登録されている場合、登録されている MBean は登録されません。既存の MBean は影響を受けず、Exception はスローされません。これは、複数のアプリケーションが共通の MBean を共有 MBeanServer で共有したい設定で役立ちます。

REPLACE_EXISTING

MBean インスタンスが同じ ObjectName にすでに登録されている場合、以前に登録された既存の MBean は登録解除され、新しい MBean がその場所に登録されます(新しい MBean は以前のインスタンスを効果的に置き換えます)。

上記の表の値は、RegistrationPolicy クラスの列挙として定義されています。デフォルトの登録動作を変更する場合は、MBeanExporter 定義の registrationPolicy プロパティの値をこれらの値のいずれかに設定する必要があります。

次の例は、デフォルトの登録動作から REPLACE_EXISTING 動作に変更する方法を示しています。

<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="registrationPolicy" value="REPLACE_EXISTING"/>
	</bean>

	<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

</beans>