21.2.输出bean到JMX
21.2. 输出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(); } }
你只需要在配置文件里简单地配置一个 MBeanExporter
的实例,并以如下所示的方法将这个bean传入,就可以将这个bean的属性和方法作为一个MBean的属性和操作暴露出去。
<beans> <!-- this bean must not be lazily initialized if the exporting is to happen --> <bean id="exporter" lazy-init="false"> <property name="beans"> <map> <entry key="bean:name=testBean1" value-ref="testBean"/> </map> </property> </bean> <bean id="testBean"> <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
。 在 第 21.4 节 “控制bean的 ObjectName
” 中描述的情况下,可以改变这个行为。
在这项配置中,testBean
这个bean在 ObjectName
值为 bean:name=testBean1
的情况下作为MBean暴露出去的。缺省情况下,这个bean所有的 public 的属性都作为对应MBean的属性, 这个bean所有的 public 的方法(除了那些继承自类 Object
的方法)都作为对应MBean的操作暴露出去的。
21.2.1. 创建一个MBeanServer
上述配置是假定应用程序运行在一个(仅有一个)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"/> <!-- 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"> <property name="beans"> <map> <entry key="bean:name=testBean1" value-ref="testBean"/> </map> </property> <property name="server" ref="mbeanServer"/> </bean> <bean id="testBean"> <property name="name" value="TEST"/> <property name="age" value="100"/> </bean> </beans>
这里,通过 MBeanServerFactoryBean
创建一个 MBeanServer
的实例,并通过属性server将这个实例提供给MBeanExporter
。 在提供你自己的MBeanServer
实例的时候,MBeanExporter
将不会去查找运行中的MBeanServer
,而是使用这个提供的MBeanServer
实例。为了让它正确的工作,必须在你的类路径上有一个JMX的实现。
21.2.2. MBean的惰性初始化
如果你用 MBeanExporter
来配置的一个bean,同时也配置了惰性初始化,那么 MBeanExporter
不会 破坏这个约定,将避免初始化相应的bean。 而是会给 MBeanServer
注册一个代理,推迟从容器中获取这个bean,直到在代理侧发生对它的第一次调用。
21.2.3. MBean的自动注册
所有通过 MBeanExporter
输出,并已经是有效MBean的bean,会在没有Spring干涉的情况下向 MBeanServer
注册。 通过设置 autodetect
属性为 true
,MBeanExporter
能自动的发现MBean:
<bean id="exporter"> <property name="autodetect" value="true"/> </bean> <bean name="spring:mbean=true"/>
这里,被称做 spring:mbean=true
的bean已经是一个有效的MBean了,将由Spring自动的注册。 缺省情况下,为JMX注册而自动发现的bean有它们自己的名字,用 ObjectName
来设置。 在 第 21.4 节 “控制bean的 ObjectName
” 章节里,更详细的描述了如何覆盖(override)这种行为。
21.2.4. 控制注册行为
考虑这样一个场景,一个Spring的 MBeanExporter
试着用 ObjectName
'bean:name=testBean1'
往一个 MBeanServer
里注册一个MBean
。 如果之前已经有一个 MBean
实例在同一个 ObjectName
下注册了,则缺省的行为是失败(并抛出一个 InstanceAlreadyExistsException
异常)。
当向 MBeanServer
注册一个 MBean
的时候,可以控制发生哪些行为。 Spring对JMX的支持三种不同的注册行为,当注册进程找到一个已经在同一个 ObjectName
下注册过的MBean
时,以此来控制注册行为。这些注册行为总结在下面的表中:
表 21.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"> <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"> <property name="name" value="TEST"/> <property name="age" value="100"/> </bean> </beans>