控制您的 Bean 的管理介面

上一節的示例中,您對 bean 的管理介面幾乎沒有控制權。每個匯出的 bean 的所有 public 屬性和方法分別被暴露為 JMX 屬性和操作。為了對匯出的 bean 中究竟哪些屬性和方法被暴露為 JMX 屬性和操作進行更細粒度的控制,Spring JMX 提供了一個全面且可擴充套件的機制來控制 bean 的管理介面。

使用 MBeanInfoAssembler API

在底層,MBeanExporter 將工作委託給 org.springframework.jmx.export.assembler.MBeanInfoAssembler API 的實現類,該類負責定義每個暴露的 bean 的管理介面。預設實現 org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler 定義了一個暴露所有公共屬性和方法的管理介面(如您在上一節示例中看到的那樣)。Spring 提供了另外兩種 MBeanInfoAssembler 介面的實現,它們允許您透過使用原始碼級元資料或任意介面來控制生成管理介面。

使用原始碼級元資料:Java 註解

透過使用 MetadataMBeanInfoAssembler,您可以使用原始碼級元資料為您的 bean 定義管理介面。元資料的讀取由 org.springframework.jmx.export.metadata.JmxAttributeSource 介面封裝。Spring JMX 提供了一個使用 Java 註解的預設實現,即 org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource。您必須為 MetadataMBeanInfoAssembler 配置一個 JmxAttributeSource 介面的實現例項才能使其正常工作,因為沒有預設實現。

要標記一個 bean 以匯出到 JMX,您應該使用 @ManagedResource 註解標註 bean 類。您必須使用 @ManagedOperation 註解標註您希望暴露為操作的每個方法,並使用 @ManagedAttribute 註解標註您希望暴露的每個屬性。在標註屬性時,您可以省略 getter 或 setter 的註解,以分別建立只寫或只讀屬性。

使用 @ManagedResource 註解的 bean 必須是公共的,暴露操作或屬性的方法也必須是公共的。

以下示例顯示了我們在建立 MBeanServer中使用的 JmxTestBean 類的註解版本。

package org.springframework.jmx;

@ManagedResource(
		objectName="bean:name=testBean4",
		description="My Managed Bean",
		log=true,
		logFile="jmx.log",
		currencyTimeLimit=15,
		persistPolicy="OnUpdate",
		persistPeriod=200,
		persistLocation="foo",
		persistName="bar")
public class AnnotationTestBean {

	private int age;
	private String name;

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

	@ManagedAttribute(description="The Age Attribute", currencyTimeLimit=15)
	public int getAge() {
		return this.age;
	}

	@ManagedAttribute(description="The Name Attribute",
			currencyTimeLimit=20,
			defaultValue="bar",
			persistPolicy="OnUpdate")
	public void setName(String name) {
		this.name = name;
	}

	@ManagedAttribute(defaultValue="foo", persistPeriod=300)
	public String getName() {
		return this.name;
	}

	@ManagedOperation(description="Add two numbers")
	@ManagedOperationParameter(name = "x", description = "The first number")
	@ManagedOperationParameter(name = "y", description = "The second number")
	public int add(int x, int y) {
		return x + y;
	}

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

}

在前面的示例中,您可以看到 AnnotationTestBean 類使用 @ManagedResource 註解進行標註,並且此 @ManagedResource 註解配置了一組屬性。這些屬性可用於配置由 MBeanExporter 生成的 MBean 的各個方面,並在Spring JMX 註解中進行更詳細的解釋。

agename 屬性都使用 @ManagedAttribute 註解進行標註,但在 age 屬性的情況下,只標註了 getter 方法。這使得這兩個屬性都作為管理屬性包含在管理介面中,但 age 屬性是隻讀的。

最後,add(int, int) 方法使用 @ManagedOperation 註解進行標註,而 dontExposeMe() 方法沒有。當您使用 MetadataMBeanInfoAssembler 時,這使得管理介面只包含一個操作(add(int, int))。

AnnotationTestBean 類不需要實現任何 Java 介面,因為 JMX 管理介面完全派生自注解。

以下配置展示瞭如何配置 MBeanExporter 以使用 MetadataMBeanInfoAssembler

<beans>

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

	<!-- will create management interface using annotation metadata -->
	<bean id="assembler"
			class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
		<property name="attributeSource" ref="jmxAttributeSource"/>
	</bean>

	<!-- will pick up the ObjectName from the annotation -->
	<bean id="namingStrategy"
			class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
		<property name="attributeSource" ref="jmxAttributeSource"/>
	</bean>

	<bean id="jmxAttributeSource"
			class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>

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

</beans>

在前面的示例中,已配置一個 MetadataMBeanInfoAssembler bean,它使用 AnnotationJmxAttributeSource 類的一個例項,並透過 assembler 屬性傳遞給 MBeanExporter。這就是利用 Spring 暴露的 MBean 的註解驅動管理介面所需的全部配置。

Spring JMX 註解

下表描述了可在 Spring JMX 中使用的註解

表 1. Spring JMX 註解
註解 應用於 描述

@ManagedResource

Class 的所有例項標記為 JMX 受管資源。

@ManagedNotification

指示由受管資源發出的 JMX 通知。

@ManagedAttribute

方法(僅 getter 和 setter)

將 getter 或 setter 標記為 JMX 屬性的一部分。

@ManagedMetric

方法(僅 getter)

將 getter 標記為 JMX 屬性,並新增描述符屬性以指示它是度量。

@ManagedOperation

方法

將方法標記為 JMX 操作。

@ManagedOperationParameter

方法

定義操作引數的描述。

下表描述了這些註解中可用的一些常用屬性。有關更多詳細資訊,請查閱每個註解的 Javadoc。

表 2. Spring JMX 註解屬性
屬性 應用於 描述

objectName

@ManagedResource

MetadataNamingStrategy 使用,用於確定受管資源的 ObjectName

description

@ManagedResource, @ManagedNotification, @ManagedAttribute, @ManagedMetric, @ManagedOperation, @ManagedOperationParameter

設定資源、通知、屬性、度量或操作的描述。

currencyTimeLimit

@ManagedResource, @ManagedAttribute, @ManagedMetric

設定 currencyTimeLimit 描述符欄位的值。

defaultValue

@ManagedAttribute

設定 defaultValue 描述符欄位的值。

log

@ManagedResource

設定 log 描述符欄位的值。

logFile

@ManagedResource

設定 logFile 描述符欄位的值。

persistPolicy

@ManagedResource, @ManagedMetric

設定 persistPolicy 描述符欄位的值。

persistPeriod

@ManagedResource, @ManagedMetric

設定 persistPeriod 描述符欄位的值。

persistLocation

@ManagedResource

設定 persistLocation 描述符欄位的值。

persistName

@ManagedResource

設定 persistName 描述符欄位的值。

name

@ManagedOperationParameter

設定操作引數的顯示名稱。

index

@ManagedOperationParameter

設定操作引數的索引。

使用 AutodetectCapableMBeanInfoAssembler 介面

為了進一步簡化配置,Spring 包含了 AutodetectCapableMBeanInfoAssembler 介面,該介面擴充套件了 MBeanInfoAssembler 介面,以增加對 MBean 資源自動檢測的支援。如果您使用 AutodetectCapableMBeanInfoAssembler 的例項配置 MBeanExporter,則允許其“投票”決定是否包含 bean 以暴露給 JMX。

AutodetectCapableMBeanInfo 介面的唯一實現是 MetadataMBeanInfoAssembler,它投票包含任何使用 ManagedResource 屬性標記的 bean。在這種情況下,預設方法是使用 bean 名稱作為 ObjectName,配置如下所示

<beans>

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<!-- notice how no 'beans' are explicitly configured here -->
		<property name="autodetect" value="true"/>
		<property name="assembler" ref="assembler"/>
	</bean>

	<bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
		<property name="attributeSource">
			<bean class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
		</property>
	</bean>

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

</beans>

請注意,在前面的配置中,沒有將任何 bean 傳遞給 MBeanExporter。但是,AnnotationTestBean 仍然會被註冊,因為它使用 @ManagedResource 註解進行標註,並且 MetadataMBeanInfoAssembler 檢測到這一點並投票包含它。這種方法的唯一缺點是 AnnotationTestBean 的名稱現在具有業務含義。您可以透過配置 ObjectNamingStrategy 來解決此問題,正如控制您的 Bean 的 ObjectName 例項中所解釋的那樣。您還可以在使用原始碼級元資料:Java 註解中看到一個使用 MetadataNamingStrategy 的示例。

使用 Java 介面定義管理介面

除了 MetadataMBeanInfoAssembler,Spring 還包含了 InterfaceBasedMBeanInfoAssembler,它允許您根據一組介面中定義的方法來約束暴露的方法和屬性。

雖然暴露 MBean 的標準機制是使用介面和簡單的命名方案,但 InterfaceBasedMBeanInfoAssembler 透過移除命名約定的需要來擴充套件了此功能,允許您使用多個介面,並消除了您的 bean 實現 MBean 介面的需要。

考慮以下介面,它用於為我們之前展示的 JmxTestBean 類定義管理介面

public interface IJmxTestBean {

	public int add(int x, int y);

	public long myOperation();

	public int getAge();

	public void setAge(int age);

	public void setName(String name);

	public String getName();

}

此介面定義了在 JMX MBean 上作為操作和屬性暴露的方法和屬性。以下程式碼展示瞭如何配置 Spring JMX 使用此介面作為管理介面的定義

<beans>

	<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
		<property name="beans">
			<map>
				<entry key="bean:name=testBean5" value-ref="testBean"/>
			</map>
		</property>
		<property name="assembler">
			<bean class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
				<property name="managedInterfaces">
					<value>org.springframework.jmx.IJmxTestBean</value>
				</property>
			</bean>
		</property>
	</bean>

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

</beans>

在前面的示例中,InterfaceBasedMBeanInfoAssembler 被配置為在為任何 bean 構建管理介面時使用 IJmxTestBean 介面。重要的是要理解,由 InterfaceBasedMBeanInfoAssembler 處理的 bean 不需要實現用於生成 JMX 管理介面的介面。

在前面的情況下,IJmxTestBean 介面被用於構建所有 bean 的所有管理介面。在許多情況下,這不是期望的行為,您可能希望為不同的 bean 使用不同的介面。在這種情況下,您可以透過 interfaceMappings 屬性將一個 Properties 例項傳遞給 InterfaceBasedMBeanInfoAssembler,其中每個條目的鍵是 bean 名稱,每個條目的值是要用於該 bean 的介面名稱的逗號分隔列表。

如果透過 managedInterfacesinterfaceMappings 屬性沒有指定管理介面,InterfaceBasedMBeanInfoAssembler 將透過反射檢查 bean,並使用該 bean 實現的所有介面來建立管理介面。

使用 MethodNameBasedMBeanInfoAssembler

MethodNameBasedMBeanInfoAssembler 允許您指定要作為屬性和操作暴露給 JMX 的方法名稱列表。以下程式碼顯示了一個示例配置

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
	<property name="beans">
		<map>
			<entry key="bean:name=testBean5" value-ref="testBean"/>
		</map>
	</property>
	<property name="assembler">
		<bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
			<property name="managedMethods">
				<value>add,myOperation,getName,setName,getAge</value>
			</property>
		</bean>
	</property>
</bean>

在前面的示例中,您可以看到 addmyOperation 方法被暴露為 JMX 操作,而 getName()setName(String)getAge() 被暴露為 JMX 屬性的相應部分。在前面的程式碼中,方法對映適用於暴露給 JMX 的 bean。為了按 bean 控制方法暴露,您可以使用 MethodNameMBeanInfoAssemblermethodMappings 屬性將 bean 名稱對映到方法名稱列表。