控制 Bean 的管理接口
在 上一节 的示例中,您对 Bean 的管理接口几乎没有控制权。每个导出的 Bean 的所有 public 属性和方法都分别作为 JMX 属性和操作公开。为了对导出的 Bean 的哪些属性和方法实际上作为 JMX 属性和操作公开进行更细粒度的控制,Infra JMX 提供了一种全面且可扩展的机制来控制 Bean 的管理接口。
使用 MBeanInfoAssembler 接口
在幕后,MBeanExporter 委托给 infra.jmx.export.assembler.MBeanInfoAssembler 接口的实现,该接口负责定义每个公开 Bean 的管理接口。默认实现 infra.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembler 定义了一个管理接口,该接口公开所有公共属性和方法(正如您在前面各节的示例中看到的那样)。Infra 提供了 MBeanInfoAssembler 接口的另外两个实现,允许您使用源代码级元数据或任何任意接口来控制生成的管理接口。
使用源代码级元数据:Java 注解
通过使用 MetadataMBeanInfoAssembler,您可以使用源代码级元数据定义 Bean 的管理接口。元数据的读取由 infra.jmx.export.metadata.JmxAttributeSource 接口封装。Infra JMX 提供了一个使用 Java 注解的默认实现,即 infra.jmx.export.annotation.AnnotationJmxAttributeSource。您必须使用 JmxAttributeSource 接口的实现实例配置 MetadataMBeanInfoAssembler 才能使其正常工作(没有默认值)。
要将 Bean 标记为导出到 JMX,您应该使用 ManagedResource 注解来注解 Bean 类。您必须使用 ManagedOperation 注解标记要公开为操作的每个方法,并使用 ManagedAttribute 注解标记要公开的每个属性。标记属性时,您可以省略 getter 或 setter 的注解,以分别创建只写或只读属性。
使用 ManagedResource 注解的 Bean 必须是公共的,公开操作或属性的方法也必须如此。
|
以下示例显示了我们在 创建 MBeanServer 中使用的 JmxTestBean 类的注解版本:
package infra.jmx;
import infra.jmx.export.annotation.ManagedResource;
import infra.jmx.export.annotation.ManagedOperation;
import infra.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="infra.jmx.export.MBeanExporter">
<property name="assembler" ref="assembler"/>
<property name="namingStrategy" ref="namingStrategy"/>
<property name="autodetect" value="true"/>
</bean>
<bean id="jmxAttributeSource"
class="infra.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<!-- 将使用注解元数据创建管理接口 -->
<bean id="assembler"
class="infra.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<!-- 将从注解中获取 ObjectName -->
<bean id="namingStrategy"
class="infra.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="jmxAttributeSource"/>
</bean>
<bean id="testBean" class="infra.jmx.AnnotationTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
在前面的示例中,MetadataMBeanInfoAssembler bean 已配置有 AnnotationJmxAttributeSource 类的实例,并通过 assembler 属性传递给 MBeanExporter。这就是利用 Infra 公开的 MBean 的元数据驱动管理接口所需的全部内容。
源代码级元数据类型
下表描述了可在 Infra JMX 中使用的源代码级元数据类型:
| 用途 | 注解 | 注解类型 |
|---|---|---|
将 |
|
Class |
将方法标记为 JMX 操作。 |
|
Method |
将 getter 或 setter 标记为 JMX 属性的一半。 |
|
Method (仅限 getters 和 setters) |
定义操作参数的描述。 |
|
Method |
下表描述了可用于这些源代码级元数据类型的配置参数:
| 参数 | 描述 | 适用于 |
|---|---|---|
|
|
|
|
设置资源、属性或操作的友好描述。 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置操作参数的显示名称。 |
|
|
设置操作参数的索引。 |
|
使用 AutodetectCapableMBeanInfoAssembler 接口
为了进一步简化配置,Infra 包含了 AutodetectCapableMBeanInfoAssembler 接口,该接口扩展了 MBeanInfoAssembler 接口以添加对 MBean 资源自动检测的支持。如果您使用 AutodetectCapableMBeanInfoAssembler 的实例配置 MBeanExporter,则允许它对包含要向 JMX 公开的 Bean 进行“投票”。
AutodetectCapableMBeanInfo 接口的唯一实现是 MetadataMBeanInfoAssembler,它投票包含标记有 ManagedResource 属性的任何 Bean。这种情况下的默认方法是使用 Bean 名称作为 ObjectName,这会导致类似于以下的配置:
<beans>
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<!-- 注意这里没有明确配置 'beans' -->
<property name="autodetect" value="true"/>
<property name="assembler" ref="assembler"/>
</bean>
<bean id="testBean" class="infra.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
<bean id="assembler" class="infra.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource">
<bean class="infra.jmx.export.annotation.AnnotationJmxAttributeSource"/>
</property>
</bean>
</beans>
请注意,在前面的配置中,没有将任何 Bean 传递给 MBeanExporter。但是,JmxTestBean 仍然被注册,因为它被标记为 ManagedResource 属性,并且 MetadataMBeanInfoAssembler 检测到这一点并投票包含它。这种方法的唯一问题是 JmxTestBean 的名称现在具有业务含义。您可以通过更改 控制 Bean 的 ObjectName 实例 中定义的 ObjectName 创建的默认行为来解决此问题。
使用 Java 接口定义管理接口
除了 MetadataMBeanInfoAssembler 之外,Infra 还包括 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 上的操作和属性公开的方法和属性。以下代码显示了如何配置 Infra JMX 以使用此接口作为管理接口的定义:
<beans>
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean5" value-ref="testBean"/>
</map>
</property>
<property name="assembler">
<bean class="infra.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
<property name="managedInterfaces">
<value>infra.jmx.IJmxTestBean</value>
</property>
</bean>
</property>
</bean>
<bean id="testBean" class="infra.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 的接口名称的逗号分隔列表。
如果未通过 managedInterfaces 或 interfaceMappings 属性指定管理接口,则 InterfaceBasedMBeanInfoAssembler 会对 Bean 进行反射,并使用该 Bean 实现的所有接口来创建管理接口。
使用 MethodNameBasedMBeanInfoAssembler
MethodNameBasedMBeanInfoAssembler 允许您指定作为属性和操作公开给 JMX 的方法名称列表。以下代码显示了一个示例配置:
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean5" value-ref="testBean"/>
</map>
</property>
<property name="assembler">
<bean class="infra.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 名称映射到方法名称列表。