控制您 Bean 的管理接口
在上一节的示例中,
您对Bean的管理接口的控制很少。每个导出Bean的所有public
属性和方法分别作为JMX属性和操作公开。为了更精细地控制哪些
属性和方法实际上作为JMX属性和操作公开,Spring JMX提供了全面且可扩展的机制来
控制您的Bean的管理接口。
使用 MBeanInfoAssembler API
在幕后,MBeanExporter 委托给 org.springframework.jmx.export.assembler.MBeanInfoAssembler API 的一个实现,该实现负责定义每个暴露的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的注解之一,从而分别创建只写或只读属性。
一个使用@0注解的Bean必须是公共的,同样,暴露操作或属性的方法也必须是公共的。 |
以下示例展示了一个带有注解的JmxTestBean类版本,我们在创建MBeanServer中使用过它。
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注解部分进行更详细的解释。
age 和 name 属性都用 @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>
在前面的例子中,一个MetadataMBeanInfoAssembler bean已经被配置为AnnotationJmxAttributeSource类的实例,并通过assembler属性传递给MBeanExporter。这就是利用注解驱动的管理接口来管理您的Spring暴露的MBeans所需的一切。
Spring JMX 注解
下表描述了可在Spring JMX中使用的注解:
| 注解 | 适用于 | 描述 |
|---|---|---|
|
类 |
将所有 |
|
类 |
表示由管理资源发出的JMX通知。 |
|
方法(仅包含 getters 和 setters) |
标记一个getter或setter为JMX属性的一半。 |
|
方法(仅包含 getters) |
标记一个getter为JMX属性,并添加描述符属性以表明其为一个度量指标。 |
|
方法 |
标记一个方法作为JMX操作。 |
|
方法 |
为操作参数定义描述。 |
下表描述了一些可用于这些注解的常见属性。有关更多详细信息,请参阅每个注解的Javadoc。
| 属性 | 适用于 | 描述 |
|---|---|---|
|
|
由 |
|
|
设置资源、通知、属性、指标或操作的描述。 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置 |
|
|
设置操作参数的显示名称。 |
|
|
设置操作参数的索引。 |
使用 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仍然被注册。这种方法的唯一缺点是AnnotationTestBean的名称现在具有业务意义。您可以通过配置ObjectNamingStrategy来解决此问题,具体方法请参阅控制Bean的ObjectName实例。您还可以在使用源代码级元数据:Java注解中看到使用MetadataNamingStrategy的示例。
通过使用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>
在前面的示例中,当为任何 bean 构建管理接口时,InterfaceBasedMBeanInfoAssembler 被配置为使用 IJmxTestBean 接口。理解这一点很重要:由 InterfaceBasedMBeanInfoAssembler 处理的 bean 不需要实现用于生成 JMX 管理接口的接口。
在前面的情况下,IJmxTestBean 接口用于构建所有 bean 的管理接口。在许多情况下,这不是期望的行为,您可能希望为不同的 bean 使用不同的接口。在这种情况下,可以通过 interfaceMappings 属性传递一个 Properties 实例,其中每个条目的键是 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 名称映射到方法名称列表。