控制您的Bean的管理接口

前一节的示例中,您对您的bean的管理接口几乎没有控制权。每个导出的bean的所有public属性和方法分别暴露为JMX属性和操作。为了更精细地控制哪些属性和方法实际上作为JMX属性和操作暴露出来,Spring JMX提供了一个全面且可扩展的机制来控制您的bean的管理接口。

使用MBeanInfoAssembler接口

MBeanExporter委托给 org.springframework.jmx.export.assembler.MBeanInfoAssembler接口的实现,负责定义每个暴露的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接口的实现实例,以使其正常工作(没有默认值)。

ManagedResource注解标记bean类。您必须使用 ManagedOperation注解标记您希望暴露为操作的每个方法,并使用 ManagedAttribute注解标记您希望暴露的每个属性。在标记属性时,您可以省略getter或setter的注解,分别创建只写或只读属性。

ManagedResource注解的bean必须是public的,暴露操作或属性的方法也必须是public的。
创建MBeanServer中使用的 JmxTestBean类的注解版本:

package org.springframework.jmx;

import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedAttribute;

@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 implements IJmxTestBean {

	private String name;
	private int age;

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

	public void setAge(int age) {
		this.age = 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 name;
	}

	@ManagedOperation(description="Add two numbers")
	@ManagedOperationParameters({
		@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();
	}

}
JmxTestBean类使用 ManagedResource注解标记,并且这个 ManagedResource注解配置了一组属性。这些属性可用于配置由 MBeanExporter生成的MBean的各个方面,稍后在 源级元数据类型中将详细解释。

agename属性都使用ManagedAttribute注解进行了标记,但是在age属性的情况下,只标记了getter。这导致这两个属性都包含在管理接口中作为属性,但age属性是只读的。

add(int, int)方法使用 ManagedOperation属性进行了标记,而 dontExposeMe()方法没有。这导致在使用 MetadataMBeanInfoAssembler时,管理接口只包含一个操作( add(int, int))。

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>

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

	<!-- 将使用注解元数据创建管理接口 -->
	<bean id="assembler"
			class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
		<property name="attributeSource" ref="jmxAttributeSource"/>
	</bean>

	<!-- 将从注解中获取ObjectName -->
	<bean id="namingStrategy"
			class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
		<property name="attributeSource" ref="jmxAttributeSource"/>
	</bean>

	<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暴露的MBeans提供优势所需的全部内容。

Source-level Metadata Types

The following table describes the source-level metadata types that are available for use in Spring JMX:

Table 1. Source-level metadata types
Purpose Annotation Annotation Type

Mark all instances of a Class as JMX managed resources.

@ManagedResource

Class

Mark a method as a JMX operation.

@ManagedOperation

Method

Mark a getter or setter as one half of a JMX attribute.

@ManagedAttribute

Method (only getters and setters)

Define descriptions for operation parameters.

@ManagedOperationParameter and @ManagedOperationParameters

Method

The following table describes the configuration parameters that are available for use on these source-level metadata types:

Table 2. Source-level metadata parameters
Parameter Description Applies to

ObjectName

Used by MetadataNamingStrategy to determine the ObjectName of a managed resource.

ManagedResource

description

Sets the friendly description of the resource, attribute or operation.

ManagedResource, ManagedAttribute, ManagedOperation, or ManagedOperationParameter

currencyTimeLimit

Sets the value of the currencyTimeLimit descriptor field.

ManagedResource or ManagedAttribute

defaultValue

Sets the value of the defaultValue descriptor field.

ManagedAttribute

log

Sets the value of the log descriptor field.

ManagedResource

logFile

Sets the value of the logFile descriptor field.

ManagedResource

persistPolicy

Sets the value of the persistPolicy descriptor field.

ManagedResource

persistPeriod

Sets the value of the persistPeriod descriptor field.

ManagedResource

persistLocation

Sets the value of the persistLocation descriptor field.

ManagedResource

persistName

Sets the value of the persistName descriptor field.

ManagedResource

name

Sets the display name of an operation parameter.

ManagedOperationParameter

index

Sets the index of an operation parameter.

ManagedOperationParameter

Using the AutodetectCapableMBeanInfoAssembler Interface

To simplify configuration even further, Spring includes the AutodetectCapableMBeanInfoAssembler interface, which extends the MBeanInfoAssembler interface to add support for autodetection of MBean resources. If you configure the MBeanExporter with an instance of AutodetectCapableMBeanInfoAssembler, it is allowed to “vote” on the inclusion of beans for exposure to JMX.

The only implementation of the AutodetectCapableMBeanInfo interface is the MetadataMBeanInfoAssembler, which votes to include any bean that is marked with the ManagedResource attribute. The default approach in this case is to use the bean name as the ObjectName, which results in a configuration similar to the following:

<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="testBean" class="org.springframework.jmx.JmxTestBean">
		<property name="name" value="TEST"/>
		<property name="age" value="100"/>
	</bean>

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

</beans>

Notice that, in the preceding configuration, no beans are passed to the MBeanExporter. However, the JmxTestBean is still registered, since it is marked with the ManagedResource attribute and the MetadataMBeanInfoAssembler detects this and votes to include it. The only problem with this approach is that the name of the JmxTestBean now has business meaning. You can address this issue by changing the default behavior for ObjectName creation as defined in Controlling ObjectName Instances for Your Beans.

通过Java接口定义管理接口

除了MetadataMBeanInfoAssembler之外,Spring还包括InterfaceBasedMBeanInfoAssembler,它允许您根据一组接口中定义的方法来限制暴露的方法和属性。

尽管暴露MBeans的标准机制是使用接口和简单的命名方案,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属性向InterfaceBasedMBeanInfoAssembler传递一个Properties实例,其中每个条目的键是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名称映射到方法名称列表。