将您的 Bean 导出到 JMX
Infra JMX 框架中的核心类是 MBeanExporter。该类负责获取您的 Infra Bean 并将它们注册到 JMX MBeanServer。例如,考虑以下类:
package infra.jmx;
public class JmxTestBean implements IJmxTestBean {
private String name;
private int age;
private boolean isSuperman;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int add(int x, int y) {
return x + y;
}
public void dontExposeMe() {
throw new RuntimeException();
}
}
要将此 Bean 的属性和方法公开为 MBean 的属性和操作,您可以在配置文件中配置 MBeanExporter 类的实例并传入该 Bean,如下例所示:
<beans>
<!-- 如果要进行导出,则此 bean 不得延迟初始化 -->
<bean id="exporter" class="infra.jmx.export.MBeanExporter" lazy-init="false">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
</bean>
<bean id="testBean" class="infra.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
前面配置片段中的相关 Bean 定义是 exporter Bean。beans 属性告诉 MBeanExporter 确切需要将哪些 Bean 导出到 JMX MBeanServer。在默认配置中,beans Map 中每个条目的键用作对应条目值引用的 Bean 的 ObjectName。您可以更改此行为,如 控制 Bean 的 ObjectName 实例 中所述。
通过此配置,testBean Bean 在 ObjectName bean:name=testBean1 下作为 MBean 公开。默认情况下,Bean 的所有 public 属性都作为属性公开,所有 public 方法(从 Object 类继承的方法除外)都作为操作公开。
MBeanExporter 是一个 Lifecycle Bean(请参阅 启动和关闭回调)。默认情况下,MBean 在应用程序生命周期中尽可能晚地导出。您可以配置导出发生的 phase,或通过设置 autoStartup 标志来禁用自动注册。
|
创建 MBeanServer
上一节 中显示的配置假设应用程序运行在一个已经运行了一个(且只有一个)MBeanServer 的环境中。在这种情况下,Infra 尝试定位正在运行的 MBeanServer 并将您的 Bean 注册到该服务器(如果有)。当您的应用程序在具有自己的 MBeanServer 的容器(如 Tomcat 或 IBM WebSphere)内运行时,此行为非常有用。
但是,这种方法在独立环境中或在不提供 MBeanServer 的容器内运行时毫无用处。为了解决这个问题,您可以通过将 infra.jmx.support.MBeanServerFactoryBean 类的实例添加到您的配置中来声明性地创建 MBeanServer 实例。您还可以通过将 MBeanExporter 实例的 server 属性的值设置为 MBeanServerFactoryBean 返回的 MBeanServer 值来确保使用特定的 MBeanServer,如下例所示:
<beans>
<bean id="mbeanServer" class="infra.jmx.support.MBeanServerFactoryBean"/>
<!--
此 bean 需要急切地预实例化才能进行导出;
这意味着它不得标记为延迟初始化
-->
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="server" ref="mbeanServer"/>
</bean>
<bean id="testBean" class="infra.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
在前面的示例中,MBeanServer 的实例由 MBeanServerFactoryBean 创建,并通过 server 属性提供给 MBeanExporter。当您提供自己的 MBeanServer 实例时,MBeanExporter 不会尝试定位正在运行的 MBeanServer,而是使用提供的 MBeanServer 实例。为了使其正常工作,您的类路径中必须有 JMX 实现。
重用现有的 MBeanServer
如果未指定服务器,MBeanExporter 会尝试自动检测正在运行的 MBeanServer。这在大多数环境中都有效,其中仅使用一个 MBeanServer 实例。但是,当存在多个实例时,导出器可能会选择错误的服务器。在这种情况下,您应该使用 MBeanServer agentId 来指示要使用哪个实例,如下例所示:
<beans>
<bean id="mbeanServer" class="infra.jmx.support.MBeanServerFactoryBean">
<!-- 指示首先查找服务器 -->
<property name="locateExistingServerIfPossible" value="true"/>
<!-- 搜索具有给定 agentId 的 MBeanServer 实例 -->
<property name="agentId" value="MBeanServer_instance_agentId>"/>
</bean>
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
...
</bean>
</beans>
对于通过查找方法检索现有 MBeanServer 具有动态(或未知)agentId 的平台或情况,您应该使用 factory-method,如下例所示:
<beans>
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="server">
<!-- 自定义 MBeanServerLocator -->
<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
</property>
</bean>
<!-- 其他 bean 在这里 -->
</beans>
延迟初始化的 MBean
如果您使用也配置为延迟初始化的 MBeanExporter 配置 Bean,则 MBeanExporter 不会破坏此契约,并避免实例化该 Bean。相反,它向 MBeanServer 注册代理,并推迟从容器获取 Bean,直到在代理上发生第一次调用。
这也会影响 FactoryBean 解析,其中 MBeanExporter 将定期自省生成的对象,从而有效地触发 FactoryBean.getObject()。为了避免这种情况,请将相应的 Bean 定义标记为 lazy-init。
MBean 的自动注册
通过 MBeanExporter 导出且已经是有效 MBean 的任何 Bean 都将按原样注册到 MBeanServer,而无需 Infra 的进一步干预。您可以通过将 autodetect 属性设置为 true 来使 MBeanExporter 自动检测 MBean,如下例所示:
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="autodetect" value="true"/>
</bean>
<bean name="spring:mbean=true" class="infra.jmx.export.TestDynamicMBean"/>
在前面的示例中,名为 spring:mbean=true 的 Bean 已经是一个有效的 JMX MBean,并且由 Infra 自动注册。默认情况下,自动检测用于 JMX 注册的 Bean 使用其 Bean 名称作为 ObjectName。您可以覆盖此行为,如 控制 Bean 的 ObjectName 实例 中详述。
控制注册行为
考虑这样一个场景:Infra MBeanExporter 尝试使用 ObjectName bean:name=testBean1 向 MBeanServer 注册 MBean。如果已经使用相同的 ObjectName 注册了 MBean 实例,则默认行为是失败(并抛出 InstanceAlreadyExistsException)。
您可以精确控制当 MBean 向 MBeanServer 注册时发生的情况。Infra JMX 支持允许三种不同的注册行为,以控制当注册过程发现 MBean 已在相同的 ObjectName 下注册时的注册行为。下表总结了这些注册行为:
| 注册行为 | 说明 |
|---|---|
|
这是默认的注册行为。如果已在相同的 |
|
如果已在相同的 |
|
如果已在相同的 |
上表中的值在 RegistrationPolicy 类上定义为枚举。如果要更改默认注册行为,则需要将 MBeanExporter 定义上的 registrationPolicy 属性的值设置为这些值之一。
以下示例显示了如何从默认注册行为更改为 REPLACE_EXISTING 行为:
<beans>
<bean id="exporter" class="infra.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
<property name="registrationPolicy" value="REPLACE_EXISTING"/>
</bean>
<bean id="testBean" class="infra.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>