控制 Bean 的管理介面

前一節的範例中,您對 Bean 的管理介面幾乎沒有控制權。每個匯出 Bean 的所有 public 屬性和方法都會分別公開為 JMX 屬性和操作。為了更精細地控制哪些匯出 Bean 的屬性和方法實際公開為 JMX 屬性和操作,Spring JMX 提供了一個全面且可擴充的機制來控制 Bean 的管理介面。

使用 MBeanInfoAssembler API

在幕後,MBeanExporter 委派給 org.springframework.jmx.export.assembler.MBeanInfoAssembler API 的實作,該 API 負責定義每個公開 Bean 的管理介面。預設實作 org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler 定義了一個管理介面,該介面公開所有 public 屬性和方法(如您在前幾節的範例中所見)。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 必須是 public,公開操作或屬性的方法也必須是 public。

以下範例顯示了我們在建立 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>

在前面的範例中,已使用 AnnotationJmxAttributeSource 類別的實例組態了 MetadataMBeanInfoAssembler Bean,並透過 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 名稱對應到方法名稱清單。