(注意:對原始帖子進行了少量編輯以提高可讀性)
Java管理擴展(JMX)技術是一種檢查或更改變量狀態或通過(例如) JConsole之類的管理GUI在(遠程)運行的應用程序中調用方法的好方法。 Spring使得在幾分鐘之內僅用很少的配置就可以將任何POJO公開為JMX MBean變得微不足道。 Spring JMX文檔非常好,但是有一段時間我一直在掙扎,因此想在這里記錄正確的解決方案。
我需要在服務器上運行的IBM JVM 1.5上使用Spring 2.5監視命令行Java應用程序。 監視將在Sun JVM 1.6上使用jconsole作為PC上的JMX客戶端執行。 以下所有XML片段均來自相應的Spring application-context.xml。
將POJO變成MBean
JMX可以公開以原語或復雜數據類型為參數的getter,setter和操作(盡管除少數特殊類型外,其他類型都要求客戶端具有類)。 您告訴Spring將POJO公開為MBean,如下所示:
<bean id="myMBean"class="my.package.JobPerformanceStats"factory-method="instance" /><bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false"><property name="beans"><map><entry key="bean:name=MyMBeanName" value-ref="myMBean"/></map></property>
</bean>
首先,您聲明一個POJO類的實例– myMBean(由于其他原因,我擁有老式的單例,并使用JobPerformanceStats.instance()訪問Bean)。 接下來,使用lazy-init =“ false”聲明一個MBeanExporter并向其介紹您的bean。 (還有其他方法可以執行此操作,包括自動發現。)然后,該bean將在其鍵(即“ bean:name = MyMBeanName”)下可見,JConsole將其顯示為“ MyMBeanName”。
注意,由于MBeanExporter使用新的java.lang.management包,因此它僅在JVM 1.5+下工作。 在JDK 1.4下,Spring會因以下錯誤而失敗:
java.lang.NoClassDefFoundError:javax / management / MBeanServerFactory
在org.springframework.jmx.support.MBeanServerFactoryBean.createMBeanServer處
默認情況下,它將公開所有公共方法和屬性。 您可以通過多種方式進行更改,例如在界面的幫助下。
如果您不是在已經提供了MBean服務器的容器中運行(在這里就是我的情況),則必須告訴Spring啟動一個容器:
<bean class="org.springframework.jmx.support.MBeanServerFactoryBean"/>
啟用遠程訪問
要使MBean可從另一臺機器訪問,必須通過聲明配置有適當通信機制的ConnectorServerFactoryBean將其公開。
通過JMXMP進行遠程訪問
默認情況下, ConnectorServerFactoryBean通過JMX消息傳遞協議(JMXMP)使用地址公開MBean。
服務:jmx:jmxmp:// localhost:9875
<bean class="org.springframework.jmx.support.ConnectorServerFactoryBean" />
但是,現成的協議不支持此協議,因此必須在MBean應用程序和jconsole客戶端的類路徑上都包含OpenDMK的一部分jmxremote_optional.jar(這是OpenDMK的一部分),以避免出現以下異常:
org.springframework.beans.factory.BeanCreationException:創建名稱為'org.springframework.jmx.support.ConnectorServerFactoryBean#0的bean時出錯? 在類路徑資源[application-context.xml]中定義:初始化方法的調用失敗; 嵌套的異常是java.net.MalformedURLException:不支持的協議:jmxmp
通過RMI進行遠程訪問
或者,您可以通過RMI公開MBean,而沒有其他依賴項:
<!--
Now expose the server for remote access via RMI
Local access: service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector
Remote access: service:jmx:rmi:///jndi/rmi://your.host:10099/myconnector
or service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector
-->
<beanclass="org.springframework.jmx.support.ConnectorServerFactoryBean"depends-on="rmiRegistry"><property name="objectName" value="connector:name=rmi" /><property name="serviceUrl"value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" />
</bean><bean id="rmiRegistry"class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"><property name="port" value="10099" />
</bean>
但是,還必須避免一些陷阱:
1.必須啟動RMI注冊表,以便連接器可以在此處注冊MBean。 它不會為你開始
2.您必須確保在連接器嘗試使用之前啟動注冊表,方法是在連接器之前聲明注冊表,或者通過使用depends-on屬性使此依賴關系顯式
如果未正確設置,則會出現如下異常:
org.springframework.beans.factory.BeanCreationException:創建名稱為'org.springframework.jmx.support.ConnectorServerFactoryBean#0的bean時出錯? 在類路徑資源[application-context.xml]中定義:初始化方法的調用失敗; 嵌套異常是java.io.IOException:無法綁定到URL [rmi:// localhost:10099 / jmxrmi]:javax.naming.ServiceUnavailableException [根本異常是java.rmi.ConnectException:連接被拒絕托管給主機:localhost; 嵌套的異常是:java.net.ConnectException:拒絕連接:connect]。
通過SSH隧道訪問的本地MBean服務器
為了提高安全性,您可能不希望通過僅從本地計算機(127.0.0.1)訪問MBean并使用SSH隧道使MBean暴露給遠程訪問,以便遠程JConsole可以將它們作為本地應用程序進行訪問。 這當然是可能的,但可能會很困難,因為通常JMX會通過RMI進行訪問,RMI 使用兩個端口 :一個用于RMI Registry,另一個用于實際服務(此處為MBean服務器),通常在運行時隨機選擇,而您d需要同時隧穿。 幸運的是, Spring使配置兩個端口成為可能 :
<beanclass="org.springframework.jmx.support.ConnectorServerFactoryBean"depends-on="rmiRegistry"><property name="objectName" value="connector:name=rmi" /><property name="serviceUrl"value="service:jmx:rmi://127.0.0.1:STUBPORT/jndi/rmi://localhost:REGISTRYPORT/myconnector" />
</bean><bean id="rmiRegistry"class="org.springframework.remoting.rmi.RmiRegistryFactoryBean"><property name="port" value="REGISTRYPORT" />
</bean>
將STUBPORT和REGISTRYPORT替換為合適的編號,然后隧道傳輸這兩個編號。 請注意,連接器的serviceUrl和RMI注冊表的端口屬性中的REGISTRYPORT號相同。
警告:上面的配置實際上并不能阻止從遠程應用程序直接訪問。 為了真正強制RMI注冊表僅偵聽來自本地主機的連接,我們可能需要在不帶Spring的Sun JVM下設置系統屬性com.sun.management.jmxremote。 另外,要強制注冊表使用IP 120.0.0.1,我們需要設置java.rmi.server.hostname = localhost(也適用于Spring)。 請參閱有關強制本地訪問的討論 。 我不確定如何使用Spring獲得相同的結果,同時仍然保留指定兩個RMI端口的功能。 還要檢查Spring RmiServiceExporter的JavaDoc。
相關文章和文檔:
- Alfresco的隧道調試和JMX (A。使用Spring)-請參見第二部分,JMX的SSH隧道
- 自定義隧道RMI代理 –使用配置的端口而不是隨機端口
- 使用SSH上的JMX監視ActiveMQ
- JMX 1.2規范和JMX 1.2遠程API規范 ; 來自JMX規范:“ MBean服務器依賴協議適配器和連接器,以使代理可以從代理JVM之外的管理應用程序訪問代理。” 另一方面, Oracle JMX頁面顯示,如果您設置com.sun.management.jmxremote(而不是…jmxremote.port),則可以“監視本地Java平臺,即在JVM上運行”。同一臺機器” –因此不一定來自同一JVM。
與Jconsole連接
啟動JConsole并鍵入適當的遠程地址,例如
服務:jmx:rmi:/// jndi / rmi://your.server.com:10099 / myconnector
如果連接到遠程計算機上的應用程序,則可以通過RMI訪問your.server.com。
關于連接URL,如果您有一個連接器,其serviceUrl為
服務:jmx:rmi:// myhost:9999 / jndi / rmi:// localhost:10099 / myconnector
然后,可以從客戶使用
服務:jmx:rmi:// myhost:9999 / jndi / rmi://your.server.com:10099 / myconnector
或簡單地
服務:jmx:rmi:/// jndi / rmi://your.server.com:10099 / myconnector
因為,根據JMX 1.2遠程API規范(第90頁):
…主機名和端口號
#(示例中為myhost:9999)不被客戶端使用,如果
#當前,本質上是注釋。 連接器服務器地址
#實際上存儲在序列化的存根(/ stub /形式)或
#目錄條目(/ jndi /格式)。
IBM JVM,JConsole和JMX配置
IBM JVM 5 SDK指南指出IBM SDK也包含JConsole并識別與JMX相關的相同系統屬性 ,即com.sun.management.jmxremote。*(盡管未提及“ com.sun.management.jmxremote”本身)。 )。
請注意,IBM JConsole有點不同,例如,它缺少“本地”選項卡,而通過指定命令行選項connection = localhost來代替它(在SDK指南中搜索“ JConsole監視工具的“本地選項卡””)。
進一步改進
JVM 1.5:公開MemoryMXBean
從Java 5.0開始,有幾個有用的平臺MBean提供有關JVM的信息,還包括java.lang.management.MemoryMXBean,可讓您查看堆使用情況,調用GC等。
您可以按如下所示將其提供給JConsole和其他JMX代理使用(盡管必須有一種更簡單的方法):
<bean class="org.springframework.jmx.export.MBeanExporter" lazy-init="false"><property name="beans"><map><entry key="bean:name=Memory2" value-ref="memProxy"/><!-- other exported beans may follow ... --></map></property>
</bean><bean id="memProxy"class="java.lang.management.ManagementFactory"factory-method="getMemoryMXBean"/>
更新:通過使用工廠方法getPlatformMBeanServer將Spring的MBeanServerFactoryBean替換為java.lang.management.ManagementFactory,似乎確實存在直接暴露平臺MBean的更好的方法。 當然,這需要JVM 1.5+。
通過密碼驗證提高安全性
通過RMI訪問MBean可能受密碼保護。 根據討論, 身份驗證是在服務器連接器上配置的 :
<beanclass="org.springframework.jmx.support.ConnectorServerFactoryBean"depends-on="rmiRegistry"><property name="objectName" value="connector:name=rmi" /><property name="serviceUrl"value="service:jmx:rmi://localhost/jndi/rmi://localhost:10099/myconnector" /><property name="environment"><!-- the following is only valid when the sun jmx implementation is used --><map><entry key="jmx.remote.x.password.file" value="etc/security/jmxremote.password"/><entry key="jmx.remote.x.access.file" value="etc/security/jmxremote.access"/></map></property>
</bean>
passwd和access文件遵循可在JDK / jre / lib / management文件夾中找到的模板。
摘要
使用Spring將POJO作為MBean公開很容易,只是不要忘記啟動MBean服務器和連接器。 對于JMXMP,請包括jmxmp_impl。 在類路徑上的jar以及對于RMI,請確保在連接器之前啟動RMI注冊表。
相關文章:
- JBoss 4.2.x Spring 3 JPA Hibernate教程
- GWT EJB3 Maven JBoss 5.1集成教程
- 調試生產服務器– Eclipse和JBoss展示
翻譯自: https://www.javacodegeeks.com/2011/02/expose-pojo-jmx-mbean-spring.html