什么是JMX
JMX(Java管理擴展),是一套給應用程序引入監控管理功能的接口。比如我們可以通過JMX來監控Tomcat的運行狀態。JMX最主要的應用場景就是中間件的監控,配置文件的在線修改配置。
相關概念
一個典型的JMX架構圖:
MBean:是Managed Bean的簡稱。在JMX中MBean代表一個被管理的資源實例,通過MBean中暴露的方法和屬性,外界可以獲取被管理的資源的狀態和操縱MBean的行為。事實上,MBean就是一個Java Object,同JavaBean模型一樣,外界使用自醒和反射來獲取Object的值和調用Object的方法,只是MBean更為復雜和高級一些。
MBeanServer:MBean生存在一個MBeanServer中。MBeanServer管理這些MBean,並且代理外界對它們的訪問。並且MBeanServer提供了一種注冊機制,是的外界可以通過名字來得到相應的MBean實例。
JMX Agent:Agent只是一個Java進程,它包括這個MBeanServer和一系列附加的MbeanService。當然這些Service也是通過MBean的形式來發布。
ObjectName:MBean在MBeanServer中的唯一標識。
Protocol Adapters and Connectors
JMX Agent通過各種各樣的Adapter和Connector來與外界(JVM之外)進行通信。同樣外界(JVM之外)也必須通過某個Adapter和Connector來向JMX Agent發送管理或控制請求。
Adapter和Connector的區別在於:Adapter是使用某種Internet協議來與JMX Agent獲得聯系,Agent端會有一個對象(Adapter)來處理有關協議的細節。比如SNMP Adapter和HTTP Adapter。而Connector則是使用類似RPC的方式來訪問Agent,在Agent端和客戶端都必須有這樣一個對象來處理相應的請求與應答。比如RMI Connector。
JMX Agent可以帶有任意多個Adapter,因此可以使用多種不同的方式訪問Agent。
jmx中的三層結構:
Instrumentation 層:Instrumentation層主要包括了一系列的接口定義和描述如何開發MBean的規范。通常JMX所管理的資源有一個或多個MBean組成,因此這個資源可以是任何由Java語言開發的組件,或是一個JavaWrapper包裝的其他語言開發的資源。
Agent 層:Agent用來管理相應的資源,並且為遠端用戶提供訪問的接口。Agent層構建在Intrumentation層之上,並且使用並管理Instrumentation層內部描述的組件。通常Agent由一個MBeanServer和多個系統服務組成。另外Agent還提供一個或多個Adapter或Connector以供外界的訪問。
JMX Agent並不關心它所管理的資源是什么。
Distributed 層:Distributed層關心Agent如何被遠端用戶訪問的細節。它定義了一系列用來訪問Agent的接口和組件,包括Adapter和Connector的描述。
- 一個java進程里面可以有多個不同名字的mBeanServer ,每個mbs都是一個獨立的容器,用了管理mbean
- 每個mbs都可以注冊多個rmi port,http port等
- platformMBeanServer 是由jvm創建的,並添加了一些系統的mbean,如cpu,內存,網絡,線程等等
MBean代碼示例
一個MBean是一個被管理的Java對象,有點類似於JavaBean,一個設備、一個應用或者任何資源都可以被表示為MBean,MBean會暴露一個接口對外,這個接口可以讀取或者寫入一些對象中的屬性,通常一個MBean需要定義一個接口,以MBean結尾, 例如: EchoMBean, 格式為XXXMBean,這個是規范,必須得遵守。
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
public class App {
public static void main(String[] args) throws Exception {
// 創建MBeanServer
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
// 新建MBean ObjectName, 在MBeanServer里標識注冊的MBean
ObjectName name = new ObjectName("com.csx.demo.spring.boot.jmx.mbean:type=Echo");
// 創建MBean,Echo類需要實現相關接口
Echo mbean = new Echo();
//注冊以后可以通過Jconsole等工具查看
// 在MBeanServer里注冊MBean, 標識為ObjectName(com.dxz.mbean:type=Echo)
mbs.registerMBean(mbean, name);
// 在MBeanServer里調用已注冊的EchoMBean的print方法
mbs.invoke(name, "print", new Object[] { "china sf"}, new String[] {"java.lang.String"});
Thread.sleep(Long.MAX_VALUE);
}
}
通過上面代碼發布Echo后,我們就可以通過Jconsole等工具查看Echo在JMX上的注冊情況了。
MBean本地連接
當我們啟動java進程后,經常會使用jps,jinfo,jmap,jstat等jdk自帶的命令去查詢進程的狀態,這其中的原理就是,當java進程啟動后,會創建一個用於本機連接的“localConnectorAddress”放到當前用戶目錄下,當使用jps等連接時,會到當前用戶目錄下取到“localConnectorAddress”這個JMX連接地址並連接。
MBean遠程連接
若想遠程連接訪問,肯定需要mBeanServer注冊一個或多個端口,如rmi端口,http端口等。有兩種方法可以配置遠程連接:
-
一種是直接在代碼里面指定rmi端口,並綁定,此種方法需要使用客戶端代碼訪問,
-
另一種代碼不用指定端口,只需要把mbean注冊到platformMBeanServer 里面,並在啟動進程時加jmx參數指定,用這種方法可以通過jconsole,jvisualvm遠程訪問。比如Tomcat的監控配置
-Dcom.sun.management.jmxremote=true 相關 JMX 代理偵聽開關
-Djava.rmi.server.hostname 服務器端的IP
-Dcom.sun.management.jmxremote.port=29094 相關 JMX 代理偵聽請求的端口
-Dcom.sun.management.jmxremote.ssl=false 指定是否使用 SSL 通訊
-Dcom.sun.management.jmxremote.authenticate=false 指定是否需要密碼驗證
通過Spring發布MBean
一些概念:
MBeanExporter: 從字面上很容易理解, 用來將一些spring的bean作為MBean暴露給MBEanServer。
MBeanServerFactoryBean: 也可以在spring中作為一個spring bean注入, 它用來將外部或者當前機器上的MBeanServer包裝成一個bean。
MBeanInfoAssembler : 用來控制作為MBean的spring bean的哪些屬性或方法將暴露出去, 以及決定何種形式的bean會被暴露成MBean. 不同的實現有不同的暴露方式。
ObjectNamingStrategy : 用來控制作為MBean暴露出去的spring bean在MBeanServer中將如何命名(ObjectName), 描述, 指定初始值等, ObjectName通常采用"域:鍵=值,鍵=值,...".
ConnectorServerFactoryBean : 用來給外界訪問當前spring中的MBeanServer bean提供一個連接器, 也就是給MBeanServer開一個外加訪問的口子, 比如"service:jmx:jmxmp://localhost:9875" 讓外界通過jmxmp協議, 通過9875端口來訪問MBeanServer, 外界要訪問MBeanServer, 必須提供一個connector. 默認連接器是jmxmp協議service:jmx:jmxmp://localhost:9875 , 也可以通過其他協議的連接器, 比如協議RMI,IIOP, Burlap,Hessian,SOAP
MBeanServerConnectionFactoryBean: 用來創建一個訪問MBeanServer的客戶端連接器, 比如MBeanServer bean暴露了一個服務器端連接器, 那么客戶端就可以通過這個連接器來訪問MBeanServer中的MBean. 可以理解為ConnectorServerFactoryBean的對應物, server與client之間就是這兩種連接器建立通訊連接
MBeanProxyFactoryBean: 用來創建客戶端訪問遠程MBeanServer中的MBean的代理, 客戶端要訪問服務器端的bean, 除了客戶端連接器之外, 還需要一個代理, 相當於一個服務器端的stub.
//將SpittleController導出為MBean
@ManagedResource(objectName="spitter:name=SpittleController3")
public class SpittleCntroller3 {
// 默認每個頁面的大小
public static final int DEFAULT_SPITTLES_PER_PAGE = 25;
// 每頁的大小
private int spittlesPerPage = DEFAULT_SPITTLES_PER_PAGE;
//@ManagedOperation@ManagedOperation注解替換@ManagedAttribute注解來標注存取器方法
@ManagedAttribute //將spittlesPerPage暴露為托管屬性
public int getSpittlesPerPage() {
return spittlesPerPage;
}
//@ManagedOperation@ManagedOperation注解替換@ManagedAttribute注解來標注存取器方法
@ManagedAttribute //將spittlesPerPage暴露為托管屬性
public void setSpittlesPerPage(int spittlesPerPage) {
this.spittlesPerPage = spittlesPerPage;
}
@RequestMapping(value = "/test3", method = GET)
public String test() {
String result = spittlesPerPage + " - test()";
System.out.println(result);
return "home";
}
}
@ManagedResource將類暴露成MBean,@ManagedAttribute暴露屬相,@ManagedOperation暴露方法。上面的配置需要開啟@EnableMBeanExport注解。
遠程MBean的暴露和訪問方法請參考博客
消息訂閱發布
另外JMX還有消息發布和訂閱功能。需要使用時可以參考。