在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(); } }
你只需要在配置文件里简单地配置一个 MBeanExporter
的实例,并以如下所示的方法将这个bean传入,就可以将这个bean的属性和方法作为一个MBean的属性和操作暴露出去。
<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
用到的每个条目的key被用做相应条目值所引用的bean的 ObjectName
。
在 第 20.4 节 “控制bean的 ObjectName
” 中描述的情况下,可以改变这个行为。
在这项配置中,testBean
这个bean在 ObjectName
值为 bean:name=testBean1
的情况下作为MBean暴露出去的。缺省情况下,这个bean所有的 public 的属性都作为对应MBean的属性,
这个bean所有的 public 的方法(除了那些继承自类 Object
的方法)都作为对应MBean的操作暴露出去的。
上述配置是假定应用程序运行在一个(仅有一个)MBeanServer
运行的环境中的。
这种情况下,Spring会试着查找运行中的 MBeanServer
并用这个server(如果有的话)来注册自己的bean。
在一个拥有自己的 MBeanServer
的容器中(如Tomcat或IBM WebSphere),这种行为是非常有用。
然而,在一个单一的环境,或运行在一个没有提供任何 MBeanServer
的容器里的情况下,这种方法毫无用处。
要处理这类问题,你可以在配置文件里添加一个类 org.springframework.jmx.support.MBeanServerFactoryBean
的实例来声明创建一个 MBeanServer
的实例。你也可以通过设置类
MBeanExporter
的 server
属性的值来确保使用一个特殊的 MBeanServer
,
这个 MBeanServer
值是由一个 MBeanServerFactoryBean
返回的;例如:
<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>
这里,通过 MBeanServerFactoryBean
创建一个 MBeanServer
的实例,并通过属性server将这个实例提供给MBeanExporter
。
在提供你自己的MBeanServer
实例的时候,MBeanExporter
将不会去查找运行中的MBeanServer
,而是使用这个提供的MBeanServer
实例。为了让它正确的工作,必须在你的类路径上有一个JMX的实现。
如果服务器没有指定,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 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
,
这时应该用factory-method:
<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> </beans>
如果你用 MBeanExporter
来配置的一个bean,同时也配置了惰性初始化,那么 MBeanExporter
不会 破坏这个约定,将避免初始化相应的bean。
而是会给 MBeanServer
注册一个代理,推迟从容器中获取这个bean,直到在代理侧发生对它的第一次调用。
所有通过 MBeanExporter
输出,并已经是有效MBean的bean,会在没有Spring干涉的情况下向 MBeanServer
注册。
通过设置 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已经是一个有效的MBean了,将由Spring自动的注册。
缺省情况下,为JMX注册而自动发现的bean有它们自己的名字,用 ObjectName
来设置。
在 第 20.4 节 “控制bean的 ObjectName
” 章节里,更详细的描述了如何覆盖(override)这种行为。
考虑这样一个场景,一个Spring的 MBeanExporter
试着用 ObjectName
'bean:name=testBean1'
往一个 MBeanServer
里注册一个MBean
。
如果之前已经有一个 MBean
实例在同一个 ObjectName
下注册了,则缺省的行为是失败(并抛出一个 InstanceAlreadyExistsException
异常)。
当向 MBeanServer
注册一个 MBean
的时候,可以控制发生哪些行为。
Spring对JMX的支持三种不同的注册行为,当注册进程找到一个已经在同一个 ObjectName
下注册过的MBean
时,以此来控制注册行为。这些注册行为总结在下面的表中:
表 20.1. 注册行为
注册行为 | 解释 |
---|---|
REGISTRATION_FAIL_ON_EXISTING |
这是缺省的注册行为。如果一个 |
REGISTRATION_IGNORE_EXISTING |
如果一个
当多个应用程序想在一个共享 |
REGISTRATION_REPLACE_EXISTING |
如果一个 |
上述各值(分别是 REGISTRATION_FAIL_ON_EXISTING
、
REGISTRATION_IGNORE_EXISTING
和
REGISTRATION_REPLACE_EXISTING
)作为常数定义在类 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>