?
? ????? PHP ??? ???? ??? ?? ??
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>
上述配置片段中,關(guān)系最大的是 exporter
Bean。beans
屬性使得
MBeanExporter
知道要將哪個Bean輸出到JMX的 MBeanServer
上去。
缺省配置中,beans
里的 Map
中的條目的key被用作相應(yīng)條目值所引用的Bean的 ObjectName
。
可以按照 第?20.4?節(jié) “控制Bean的ObjectName
” 描述的那樣改變這種行為。
在這個配置里,testBean
就以 bean:name=testBean1
這個 ObjectName
暴露成了一個MBean。
默認情況下,Bean中所有 public 的屬性被暴露為屬性,所有的 public 方法(除了那些從 Object
類繼承過來的之外)都被暴露為操作。
上述配置是假設(shè)了應(yīng)用程序運行在這樣的環(huán)境中,一個有且僅有一個在運作中的 MBeanServer
的環(huán)境。
這種情況下,Spring將試圖定位該 MBeanServer
,之后將你的Bean(如果有的話)注冊到該服務(wù)器上。
在自帶 MBeanServer
的容器(例如Tomcat或者IBM WebSphere)中,這種行為是很有用的。
然而,在一個孤立的環(huán)境,或者不提供 MBeanServer
的容器中,這種方法毫無用武之地。
要處理這類問題,你應(yīng)該創(chuàng)建一個 MBeanServer
實例,也就是聲明式地將 org.springframework.jmx.support.MBeanServerFactoryBean
實例添加到你的配置里。
通過設(shè)置 MBeanExporter
的 server
屬性的值,
你也可以確保 MBeanExporter
使用了 MBeanServerFactoryBean
返回的特定的 MBeanServer
。
例如:
<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
<!--
要觸發(fā)輸出,必須預(yù)先實例化這個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
創(chuàng)建的 MBeanServer
實例,它通過屬性server提供給了 MBeanExporter
。
當你提供了你自己的 MBeanServer
實例后,MBeanExporter
將使用該實例,且不再查找一個運行中的 MBeanServer
。為了使之正確工作,當然了,你必須確保你的類路徑上存在一個JMX實現(xiàn)。
如果不指定任何服務(wù)器,MBeanExporter
將自動檢測一個運行中的 MBeanServer
。
這在只有一個 MBeanServer
的情況下可以奏效,當存在多個 MBeanServer
的時候,
MBeanExporter
可能會選錯服務(wù)器。這種情況下,應(yīng)該使用 MBeanServer
的 agentId
來指定究竟使用哪個服務(wù)器。
<beans>
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<!-- 說明首先要查找一個服務(wù)器 -->
<property name="locateExistingServerIfPossible" value="true"/>
<!-- 根據(jù)給定的agentId查找對應(yīng)的 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
有一個動態(tài)(或者未知)的要通過lookup方法獲取的 agentId
。
這時就應(yīng)該用 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的時刻,直到在代理端發(fā)生對它的第一次調(diào)用。
要通過 MBeanExporter
輸出的任意的Bean,并已是有效的MBean,將會被注冊到 MBeanServer
上去,而無須Spring的干預(yù)。
通過設(shè)置屬性 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就已經(jīng)是一個有效的JMX MBean了。它將會被Spring自動注冊。
缺省情況下,那些做自動JMX注冊的Bean的 ObjectName
就是它的Bean名稱。
標題為 第?20.4?節(jié) “控制Bean的ObjectName
” 的章節(jié)里詳細的描述了如何覆蓋(overridden)這種行為。
考慮這樣的場景,一個Spring MBeanExporter
試圖用 ObjectName
'bean:name=testBean1'
向 MBeanServer
注冊一個MBean。
如果已經(jīng)存在一個同樣 ObjectName
的 MBean
實例,缺省行為是失敗(并且拋出一個 InstanceAlreadyExistsException
)。
MBean
時發(fā)生哪種行為。
Spring的JMX支持提供三種不同的注冊行為,以此來控制注冊進程發(fā)現(xiàn)一個 MBean
已經(jīng)用同樣的 ObjectName
注冊的情況。下面的表格總結(jié)了這些注冊行為:
表?20.1.?注冊行為
注冊行為 | 說明 |
---|---|
|
這是缺省的注冊行為。如果一個 |
|
如果一個 |
|
如果一個 |
MBeanRegistrationSupport
類以常量的方式定義了上述這些值(MBeanExporter
繼承了這個父類)。如果你向改變?nèi)笔〉淖孕袨椋阒恍枰獙?MBeanExporter
的屬性 registrationBehaviorName
的值設(shè)置為上述這些值之一。
以下例子闡明了如何將缺省注冊行為改變?yōu)?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>