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中的属性和方法暴露成为一个JMX MBean中的属性和操作,你只要在配置文件中简单的配置 MBeanExporter
一个实例,并且按照如下方法将这个Bean传入:
<beans> <!-- 如果要暴露,这个Bean一定 不 可以延迟初始化。--> <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>
上述配置片段中,关系最大的是 exporter
Bean。beans
属性使得
MBeanExporter
知道要将哪个Bean输出到JMX的 MBeanServer
上去。
缺省配置中,beans
里的 Map
中的条目的key被用作相应条目值所引用的Bean的 ObjectName
。
可以按照 第 20.4 节 “控制Bean的ObjectName
” 描述的那样改变这种行为。
在这个配置里,testBean
就以 bean:name=testBean1
这个 ObjectName
暴露成了一个MBean。
默认情况下,Bean中所有 public 的属性被暴露为属性,所有的 public 方法(除了那些从 Object
类继承过来的之外)都被暴露为操作。
上述配置是假设了应用程序运行在这样的环境中,一个有且仅有一个在运作中的 MBeanServer
的环境。
这种情况下,Spring将试图定位该 MBeanServer
,之后将你的Bean(如果有的话)注册到该服务器上。
在自带 MBeanServer
的容器(例如Tomcat或者IBM WebSphere)中,这种行为是很有用的。
然而,在一个孤立的环境,或者不提供 MBeanServer
的容器中,这种方法毫无用武之地。
要处理这类问题,你应该创建一个 MBeanServer
实例,也就是声明式地将 org.springframework.jmx.support.MBeanServerFactoryBean
实例添加到你的配置里。
通过设置 MBeanExporter
的 server
属性的值,
你也可以确保 MBeanExporter
使用了 MBeanServerFactoryBean
返回的特定的 MBeanServer
。
例如:
<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<!--
要触发输出,必须预先实例化这个Bean,一定 不 可以标志为延迟初始化。
-->
<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>
这里有一个由 MBeanServerFactoryBean
创建的 MBeanServer
实例,它通过属性server提供给了 MBeanExporter
。
当你提供了你自己的 MBeanServer
实例后,MBeanExporter
将使用该实例,且不再查找一个运行中的 MBeanServer
。为了使之正确工作,当然了,你必须确保你的类路径上存在一个JMX实现。
如果不指定任何服务器,MBeanExporter
将自动检测一个运行中的 MBeanServer
。
这在只有一个 MBeanServer
的情况下可以奏效,当存在多个 MBeanServer
的时候,
MBeanExporter
可能会选错服务器。这种情况下,应该使用 MBeanServer
的 agentId
来指定究竟使用哪个服务器。
<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<!-- 说明首先要查找一个服务器 -->
<property name="locateExistingServerIfPossible" value="true"/>
<!-- 根据给定的agentId查找对应的 MBeanServer
实例 -->
<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
有一个动态(或者未知)的要通过lookup方法获取的 agentId
。
这时就应该用 factory-method。
<beans>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server">
<!-- 自定义MBeanServerLocator
-->
<bean class="platform.package.MBeanServerLocator" factory-method="locateMBeanServer"/>
</property>
<!-- 其他Bean -->
</bean>
</beans>
如果你在 MBeanExporter
上配置了一个Bean,而这个 MBeanExporter
又配置了延迟初始化,那么 MBeanExporter
遵循这种契约,避免初始化这个Bean。相反,它会在 MBeanServer
上注册一个代理,推延从容器获取这个Bean的时刻,直到在代理端发生对它的第一次调用。
要通过 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的 ObjectName
就是它的Bean名称。
标题为 第 20.4 节 “控制Bean的ObjectName
” 的章节里详细的描述了如何覆盖(overridden)这种行为。
考虑这样的场景,一个Spring MBeanExporter
试图用 ObjectName
'bean:name=testBean1'
向 MBeanServer
注册一个MBean。
如果已经存在一个同样 ObjectName
的 MBean
实例,缺省行为是失败(并且抛出一个 InstanceAlreadyExistsException
)。
MBean
时发生哪种行为。
Spring的JMX支持提供三种不同的注册行为,以此来控制注册进程发现一个 MBean
已经用同样的 ObjectName
注册的情况。下面的表格总结了这些注册行为:
表 20.1. 注册行为
注册行为 | 说明 |
---|---|
|
这是缺省的注册行为。如果一个 |
|
如果一个 |
|
如果一个 |
MBeanRegistrationSupport
类以常量的方式定义了上述这些值(MBeanExporter
继承了这个父类)。如果你向改变缺省的注册行为,你只需要将 MBeanExporter
的属性 registrationBehaviorName
的值设置为上述这些值之一。
以下例子阐明了如何将缺省注册行为改变为 REGISTRATION_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="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/> </bean> <bean id="testBean" class="org.springframework.jmx.JmxTestBean"> <property name="name" value="TEST"/> <property name="age" value="100"/> </bean> </beans>