将您的 Bean 导出到 JMX
Spring JMX 框架中的核心类是 MBeanExporter
。此类负责获取您的 Spring Bean 并将其注册到 JMX MBeanServer
。例如,考虑以下类
package org.springframework.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>
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.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="org.springframework.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 将作为 MBean 公开,其 ObjectName
为 bean:name=testBean1
。默认情况下,bean 的所有 public
属性都将公开为属性,所有 public
方法(除从 Object
类继承的方法外)都将公开为操作。
MBeanExporter 是一个 Lifecycle bean(参见 启动和关闭回调)。默认情况下,MBean 在应用程序生命周期中尽可能晚地导出。您可以配置导出发生的 phase ,或者通过设置 autoStartup 标志来禁用自动注册。
|
创建 MBeanServer
前面部分中显示的配置假设应用程序正在运行在具有一个(且只有一个)正在运行的 MBeanServer
的环境中。在这种情况下,Spring 会尝试找到正在运行的 MBeanServer
,并将您的 bean 注册到该服务器(如果有)。当您的应用程序在具有自己的 MBeanServer
的容器(如 Tomcat 或 IBM WebSphere)中运行时,此行为很有用。
但是,这种方法在独立环境中或在不提供 MBeanServer
的容器中运行时毫无用处。为了解决这个问题,您可以通过在配置中添加 org.springframework.jmx.support.MBeanServerFactoryBean
类的实例来声明式地创建 MBeanServer
实例。您还可以通过将 MBeanExporter
实例的 server
属性的值设置为 MBeanServerFactoryBean
返回的 MBeanServer
值来确保使用特定的 MBeanServer
,如下例所示
<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<!--
this bean needs to be eagerly pre-instantiated in order for the exporting to occur;
this means that it must not be marked as lazily initialized
-->
<bean id="exporter" class="org.springframework.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="org.springframework.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="org.springframework.jmx.support.MBeanServerFactoryBean">
<!-- indicate to first look for a server -->
<property name="locateExistingServerIfPossible" value="true"/>
<!-- search for the MBeanServer instance with the given agentId -->
<property name="agentId" value="MBeanServer_instance_agentId>"/>
</bean>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server" ref="mbeanServer"/>
...
</bean>
</beans>
对于平台或现有 MBeanServer
具有动态(或未知)agentId
的情况,该 agentId
是通过查找方法获取的,您应该使用 工厂方法,如下例所示
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server">
<!-- Custom MBeanServerLocator -->
<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
</property>
</bean>
<!-- other beans here -->
</beans>
延迟初始化的 MBean
如果您配置了一个 bean,该 bean 具有一个 MBeanExporter
,该 MBeanExporter
也配置为延迟初始化,那么 MBeanExporter
不会破坏此契约,并避免实例化该 bean。相反,它会在 MBeanServer
中注册一个代理,并推迟从容器中获取 bean,直到代理上的第一次调用发生。
这也影响 FactoryBean
解析,其中 MBeanExporter
会定期内省生成的 对象,有效地触发 FactoryBean.getObject()
。为了避免这种情况,请将相应的 bean 定义标记为延迟初始化。
自动注册 MBean
通过 MBeanExporter
导出的任何 bean,如果已经是有效的 MBean,则会按原样在 MBeanServer
中注册,无需 Spring 的进一步干预。您可以通过将 autodetect
属性设置为 true
来使 MBeanExporter
自动检测 MBean,如下例所示
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="autodetect" value="true"/>
</bean>
<bean name="spring:mbean=true" class="org.springframework.jmx.export.TestDynamicMBean"/>
在前面的示例中,名为 spring:mbean=true
的 bean 已经是有效的 JMX MBean,并由 Spring 自动注册。默认情况下,自动检测到用于 JMX 注册的 bean 会使用其 bean 名称作为 ObjectName
。您可以覆盖此行为,如 控制 bean 的 ObjectName
实例 中所述。
控制注册行为
考虑以下场景:Spring MBeanExporter
尝试使用 ObjectName
bean:name=testBean1
在 MBeanServer
中注册 MBean
。如果 MBean
实例已在同一个 ObjectName
下注册,则默认行为是失败(并抛出 InstanceAlreadyExistsException
)。
您可以控制在 MBean
注册到 MBeanServer
时确切发生的情况。Spring 的 JMX 支持允许使用三种不同的注册行为来控制在注册过程中发现 MBean
已在同一个 ObjectName
下注册时的注册行为。下表总结了这些注册行为
注册行为 | 解释 |
---|---|
|
这是默认的注册行为。如果一个 |
|
如果一个 |
|
如果一个 |
上表中的值在 RegistrationPolicy
类中定义为枚举。如果您想更改默认的注册行为,您需要将 MBeanExporter
定义中的 registrationPolicy
属性的值设置为这些值之一。
以下示例展示了如何将默认注册行为更改为 REPLACE_EXISTING
行为
<beans>
<bean id="exporter" class="org.springframework.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="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>