控制 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
。您必须使用JmxAttributeSource
接口的实现实例配置MetadataMBeanInfoAssembler
,才能使其正常工作(没有默认值)。
要将 bean 标记为导出到 JMX,您应该使用ManagedResource
注解注释 bean 类。您必须使用ManagedOperation
注解标记您希望公开为操作的每个方法,并使用ManagedAttribute
注解标记您希望公开的每个属性。在标记属性时,您可以省略 getter 或 setter 的注解,分别创建只写或只读属性。
ManagedResource 注释的 bean 必须是公共的,公开操作或属性的方法也必须是公共的。
|
以下示例展示了我们在创建 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 的各个方面,并在后面的源代码级元数据类型中详细说明。
age
和 name
属性都用 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"/>
<!-- 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 的源代码级元数据类型。
目的 | 注释 | 注释类型 |
---|---|---|
将 |
|
Class |
将方法标记为 JMX 操作。 |
|
Method |
将 getter 或 setter 标记为 JMX 属性的一半。 |
|
Method (仅 getter 和 setter) |
定义操作参数的描述。 |
|
Method |
下表描述了可用于这些源代码级元数据类型的配置参数。
参数 | 描述 | 应用于 |
---|---|---|
|
由 |
|
|
设置资源、属性或操作的友好描述。 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置操作参数的显示名称。 |
|
|
设置操作参数的索引。 |
|
使用 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="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 使用不同的接口。在这种情况下,您可以通过 interfaceMappings
属性将 Properties
实例传递给 InterfaceBasedMBeanInfoAssembler
,其中每个条目的键是 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 级别的方法公开,您可以使用 MethodNameMBeanInfoAssembler
的 methodMappings
属性将 bean 名称映射到方法名称列表。