將您的 Bean 匯出到 JMX
Spring JMX框架的核心類是 MBeanExporter。這個類負責獲取你的Spring Bean並將其註冊到JMX MBeanServer 中。例如,考慮以下類
-
Java
-
Kotlin
public class JmxTestBean implements IJmxTestBean {
private String name;
private int age;
@Override
public int getAge() {
return age;
}
@Override
public void setAge(int age) {
this.age = age;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public int add(int x, int y) {
return x + y;
}
@Override
public void dontExposeMe() {
throw new RuntimeException();
}
}
class JmxTestBean : IJmxTestBean {
override lateinit var name: String
override var age = 0
override fun add(x: Int, y: Int): Int {
return x + y
}
override fun dontExposeMe() {
throw RuntimeException()
}
}
要將此Bean的屬性和方法作為MBean的屬性和操作公開,您可以在配置檔案中配置 MBeanExporter 類的一個例項並傳入該Bean,示例如下
-
Java
-
Kotlin
-
Xml
@Configuration
public class JmxConfiguration {
@Bean
MBeanExporter exporter(JmxTestBean testBean) {
MBeanExporter exporter = new MBeanExporter();
exporter.setBeans(Map.of("bean:name=testBean1", testBean));
return exporter;
}
@Bean
JmxTestBean testBean() {
JmxTestBean testBean = new JmxTestBean();
testBean.setName("TEST");
testBean.setAge(100);
return testBean;
}
}
@Configuration
class JmxConfiguration {
@Bean
fun exporter(testBean: JmxTestBean) = MBeanExporter().apply {
setBeans(mapOf("bean:name=testBean1" to testBean))
}
@Bean
fun testBean() = JmxTestBean().apply {
name = "TEST"
age = 100
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- this bean must not be lazily initialized if the exporting is to happen -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
</bean>
<bean id="testBean" class="org.example.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>
上一個配置片段中的相關Bean定義是 exporter Bean。beans 屬性告訴 MBeanExporter 確切地哪些Bean必須匯出到JMX MBeanServer。在預設配置中,beans Map 中每個條目的鍵用作相應條目值引用的Bean的 ObjectName。您可以更改此行為,如 控制Bean的ObjectName例項 中所述。
透過此配置,testBean Bean在 ObjectName bean:name=testBean1 下公開為MBean。預設情況下,Bean的所有 public 屬性都作為屬性公開,所有 public 方法(除了從 Object 類繼承的方法)都作為操作公開。
MBeanExporter 是一個 Lifecycle Bean(參見 啟動和關閉回撥)。預設情況下,MBeans在應用程式生命週期中儘可能晚地匯出。您可以配置匯出發生的 phase 或透過設定 autoStartup 標誌停用自動註冊。 |
建立MBeanServer
上一節中顯示的配置假設應用程式在一個已經有一個(並且只有一個)MBeanServer 執行的環境中執行。在這種情況下,Spring會嘗試定位正在執行的 MBeanServer 並將您的Bean註冊到該伺服器(如果有)。當您的應用程式在具有自己 MBeanServer 的容器(如Tomcat或IBM WebSphere)中執行時,此行為非常有用。
然而,在獨立環境或在不提供 MBeanServer 的容器中執行時,此方法毫無用處。為了解決這個問題,您可以透過在配置中新增 org.springframework.jmx.support.MBeanServerFactoryBean 類的一個例項來宣告性地建立一個 MBeanServer 例項。您還可以透過將 MBeanExporter 例項的 server 屬性的值設定為由 MBeanServerFactoryBean 返回的 MBeanServer 值來確保使用特定的 MBeanServer,示例如下
<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實現。
重用現有 MBeanServer
如果未指定伺服器,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 for 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,並透過查詢方法檢索的平臺或情況,您應該使用 工廠方法,示例如下
<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>
<!-- other beans here -->
</beans>
延遲初始化的MBeans
如果您使用 MBeanExporter 配置了一個Bean,並且該Bean也配置為延遲初始化,MBeanExporter 不會違反此約定,並避免例項化該Bean。相反,它會向 MBeanServer 註冊一個代理,並將從容器中獲取Bean的操作推遲到代理上的第一次呼叫發生時。
這也會影響 FactoryBean 解析,其中 MBeanExporter 會定期檢查生成物件,從而有效地觸發 FactoryBean.getObject()。為了避免這種情況,請將相應的Bean定義標記為延遲初始化。
MBeans的自動註冊
任何透過 MBeanExporter 匯出且已經是有效MBean的Bean都將原樣註冊到 MBeanServer,而無需Spring進一步干預。您可以透過將 autodetect 屬性設定為 true 來使 MBeanExporter 自動檢測MBeans,示例如下
<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會將其Bean名稱用作 ObjectName。您可以覆蓋此行為,詳見 控制Bean的ObjectName例項。
控制註冊行為
考慮一個場景,Spring MBeanExporter 嘗試使用 ObjectName bean:name=testBean1 將一個 MBean 註冊到 MBeanServer。如果一個 MBean 例項已經在此相同的 ObjectName 下注冊,預設行為是失敗(並丟擲 InstanceAlreadyExistsException)。
您可以精確控制當一個 MBean 註冊到 MBeanServer 時會發生什麼。Spring的JMX支援允許三種不同的註冊行為來控制當註冊過程發現一個 MBean 已經註冊在相同的 ObjectName 下時的註冊行為。下表總結了這些註冊行為
| 註冊行為 | 解釋 |
|---|---|
|
這是預設的註冊行為。如果一個 |
|
如果一個 |
|
如果一個 |
上表中定義的值是 RegistrationPolicy 類上的列舉。如果您想更改預設註冊行為,您需要將 MBeanExporter 定義上的 registrationPolicy 屬性值設定為其中一個值。
以下示例顯示瞭如何從預設註冊行為更改為 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="registrationPolicy" value="REPLACE_EXISTING"/>
</bean>
<bean id="testBean" class="org.springframework.jmx.JmxTestBean">
<property name="name" value="TEST"/>
<property name="age" value="100"/>
</bean>
</beans>