在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>