|
对于最新稳定版本,请使用 Spring Framework 7.0.6! |
控制您的 Bean 的管理接口
在前一节的示例中,
您对 bean 的管理接口几乎没有控制权。每个导出的 bean 的所有public
属性和方法分别被暴露为 JMX 属性和操作。为了更精细地控制导出的 bean 中
哪些属性和方法实际被暴露为 JMX 属性和操作,Spring JMX 提供了一套全面且可扩展的机制,
用于控制 bean 的管理接口。
使用MBeanInfoAssembler接口
在幕后,MBeanExporter 会委托给一个实现了
org.springframework.jmx.export.assembler.MBeanInfoAssembler 接口的类,
该类负责定义每个被暴露 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 必须是 public 的,暴露操作或属性的方法也必须是 public 的。 |
以下示例展示了我们在创建 MBeanServer中使用的exporting.html#jmx-exporting-mbeanserver类的注解版本:
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 的各个方面,具体细节将在后面的源码级元数据类型一节中详细说明。
age 和 name 两个属性都使用了 ManagedAttribute 注解,但在 age 属性的情况下,仅 getter 方法被标记。
这会导致这两个属性都被包含在管理接口中作为属性,但 age 属性是只读的。
最后,add(int, int) 方法使用了 ManagedOperation 注解进行标记,
而 dontExposeMe() 方法则没有。当你使用 add(int, int) 时,
这将导致管理接口仅包含一个操作(即 MetadataMBeanInfoAssembler)。
以下配置展示了如何配置 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"/>
<!-- 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="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 中使用的源代码级元数据类型:
| 目的 | 注解 | 注解类型 |
|---|---|---|
将某个 |
|
类 |
将一个方法标记为 JMX 操作。 |
|
方法 |
将一个 getter 或 setter 方法标记为 JMX 属性的一半。 |
|
方法(仅限 getter 和 setter) |
为操作参数定义描述。 |
|
方法 |
下表描述了可在这些源代码级元数据类型上使用的配置参数:
| 参数 | <description> </description> | 适用范围 |
|---|---|---|
|
由 |
|
|
设置资源、属性或操作的友好描述。 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置操作参数的显示名称。 |
|
|
设置操作参数的索引。 |
|
使用AutodetectCapableMBeanInfoAssembler接口
为了进一步简化配置,Spring 提供了 AutodetectCapableMBeanInfoAssembler 接口,该接口扩展了 MBeanInfoAssembler 接口,以增加对 MBean 资源自动检测的支持。如果你使用 MBeanExporter 的实例来配置 AutodetectCapableMBeanInfoAssembler,它就可以对是否将某个 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="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>
请注意,在上述配置中,没有将任何 bean 传递给 MBeanExporter。
然而,JmxTestBean 仍然被注册,因为它标记有 ManagedResource
属性,且 MetadataMBeanInfoAssembler 会检测到这一点并投票决定将其包含在内。
这种方法唯一的问题在于,JmxTestBean 的名称现在具有业务含义。您可以通过更改在 控制 Bean 的 ObjectName 实例 中定义的 ObjectName 创建的默认行为来解决此问题。
通过使用 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 使用不同的接口。此时,你可以通过 InterfaceBasedMBeanInfoAssembler 属性向 Properties 传入一个 interfaceMappings 实例,其中每个条目的键是 Bean 的名称,值则是该 Bean 所应使用的一组以逗号分隔的接口名称列表。
如果未通过 managedInterfaces 或 interfaceMappings 属性指定管理接口,则 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>
在前面的示例中,您可以看到 add 和 myOperation 方法被暴露为 JMX 操作,而 getName()、setName(String) 和 getAge() 则被暴露为 JMX 属性的相应部分(读取或写入方法)。在上述代码中,这些方法映射适用于暴露给 JMX 的 Bean。若要逐个 Bean 地控制方法的暴露行为,您可以使用 methodMappings 的 MethodNameMBeanInfoAssembler 属性,将 Bean 名称映射到对应的方法名称列表。