JMX 介紹

1. 什麼是 JMX

         JMX (Java Management Extensions)是一個爲應用程序,設備,系統等植入管理功能的框架。

        JMX 規範可以分爲三層: 設備層, 代理層, 分佈式服務層。 設備層規範定義了編寫可由 JMX 管理的資源的標準,即如何寫 MBean; 代理曾規範定義了創建代理的規範,封裝了 MBean Server;分佈式服務層主要定義了對代理層進行操作的管理接口和構件。

        如果一個 Java 對象可以由一個遵循 JMX 規範的管理器應用管理,那麼這個Java 對象就可以稱爲一個可由 JMX 管理的資源。

        要使一個 Java 對象可管理,則必須創建相應的 MBean 對象,並通過這些 MBean 對象管理相應的 Java 對象。當擁有 MBean 類後,需要將其實例化並註冊到 MBeanServer 上。

       一共有四種類型的 MBean , 分別是標準類型 MBean, 動態類型 MBean, 開放類型 MBean 和模型類型 MBean。我們在下文將分別進行介紹。

2. JMX API 簡單介紹

        本部分對 JMX 中常用的一些類進行簡單的介紹。

2.1 MBeanServer

public ObjectInstance createMBean(String className, ObjectName name).

        創建 MBean,並將其註冊到 MBeanServer.

public ObjectInstance registerMBean(Object object, ObjectName name).

        將Java對象註冊到 MBeanServer。

public Set queryNames(ObjectName name, QueryExp query).

        根據對象名查找註冊的 MBean, 返回的 Set 中包含的是查找到的 MBean  對應的 ObjectName。

public Set queryMBeans(ObjectName name, QueryExp query).

        返回的 Set 中包含的是 ObjectInstance 對象。

pubilc Attribute getAttribute(ObjectName name, String attributeName).

        返回指定 name 代表的 MBean 的名爲 attributeName 的屬性。

public void setAttribute(ObjectName name, Attribute attr).

        設置屬性

public invoke(ObjectName name, String methodName, ..., ...).

       執行 指定 MBean 的指定方法。

2.2 MBeanServerFactory

public static MBeanServer createMBeanServer().

        創建 MBeanServer.

2.3 ObjectName

        ObjectName 由兩部分組成: domain 和 鍵/值對。如下面是一個是一個有效的對象名稱:

        myDomain:type=Car,color=blue

public ObjectName(String name).

        根據 name 構造ObjectName  對象。

2.4 ObjectInstance

2.5 Attribute

3. 標準 MBean

        標準 MBean 是最簡單的 MBean 類型。通過標準 MBean 來管理一個 Java 對象需要以下步驟:

        1. 創建一個接口, 命名規範爲: Java 類名 + MBean 後綴。如 Java 類爲 Car ,則需要創建 CarMBean 接口。

        2. 修改 Java 類,使它實現創建的接口。如上面提到的 CarMBean。

        3. 創建代理,該代理包含 MBeanServer 實例。

        4. 爲 MBean 創建 ObjectName 實例。

        5. 實例化 MBeanServer。

        6. 將 MBean 註冊到 MBeanServer。

        下面我們介紹一個標準 MBean 的例子。如我們有一個 Car 類:

package test;

public class Car{
	private String color = "red";
	
	public String getColor(){
		return color;
	}
	public void setColor(String color){
		this.color = color;
	}
	public void drive(){
		System.out.println("Baby you can drive my car.");
	}
}
        那麼,第一步我們需要創建 名字爲 CarMBean 的接口:

package test;

public interface CarMBean {
	public String getColor();
	public void setColor(String color);
	public void drive();
}

        接下類使 Car 實現 CarMBean:

package test;

public class Car implements CarMBean{
	private String color = "red";
	
	public String getColor(){
		return color;
	}
	public void setColor(String color){
		this.color = color;
	}
	public void drive(){
		System.out.println("Baby you can drive my car.");
	}
}

        然後創建代理:

package test;

import javax.management.Attribute;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;

public class StandardAgent {
	private MBeanServer mBeanServer = null;
	public StandardAgent(){
		mBeanServer = MBeanServerFactory.newMBeanServer();
	}
	
	public MBeanServer getMBeanServer(){
		return mBeanServer;
	}
	
	public ObjectName createObjectName(String name){
		ObjectName objectName = null;
		try{
			objectName = new ObjectName(name);
		}catch(Exception e){
		}
		return objectName;
	}
	private void createStandardBean(ObjectName objectName, String managedResourceClassName){
		try{
			mBeanServer.createMBean(managedResourceClassName, objectName);
		}catch(Exception e){}
	}
	
	public static  void main(String[] args){
		StandardAgent agent = new StandardAgent();
		MBeanServer mBeanServer = agent.getMBeanServer();
		String domain = mBeanServer.getDefaultDomain();
		String managedResourceClassName = "test.Car";
		ObjectName objectName = agent.createObjectName(domain + ":type=" + managedResourceClassName);
		System.out.println("objectName: " + objectName);
		agent.createStandardBean(objectName, managedResourceClassName);
		
		try{
			Attribute colorAttribute = new Attribute("Color", "blue");
			mBeanServer.setAttribute(objectName, colorAttribute);
			System.out.println(mBeanServer.getAttribute(objectName, "Color"));
			mBeanServer.invoke(objectName, "drive", null, null);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}

         該類的 main() 方法首先創建 StandardAgent 的一個實例,並獲取 MBeanServer。然後創建 ObjectName 實例,並使用 MBeanServer的默認域作爲ObjectName 的域。然後通過 CarMBean 實例來管理 Car 對象。

4. 動態 MBean(略)

5. 開放 MBean (略)

6. 模型 MBean

        相對於標準 MBean,模型 MBean 更加靈活。如果我們不能修改已有的 Java 類,那麼使用模型 MBean 是不錯的選擇。不過,模型 MBean 直接變成的難度更大一些。後面我們會介紹到使用 Apache 的 Common Modeler 來簡化模型 MBean 過程。

6.1 模型 MBean 的相關類和接口

ModelMBean 接口

        使用模型 MBean,我們不需要像在標準 MBean 中那樣定義接口。使用 ModelMBean 接口是不錯的選擇。

RequiredModelMBean 類

        JMX 的參考實現中的一個 ModelMBean 接口的默認實現類。

ModelMBeanInfo 接口

        編寫模型 MBean 的最大挑戰是告訴 ModelMBean 對象託管資源的哪些屬性和方法可以暴露給代理。ModelMBeanInfo 對象描述了將會暴露給代理的構造函數、屬性、操作甚至是監聽器。

        創建了 ModelMBeanInfo 對象後,需要將其與 ModelMBean 對象關聯。目前有兩種方式可以做到這一點:

        1) 傳入 ModelMBeanInfo 對象給 RequiredModelMBean 對象的構造函數。

        2) 調用 RequiredModelMBean 對象的 setModelMBeanInfo 方法。

        創建了 ModelMBean 對象後,需要調用 ModelMBean 接口的 setManagedResource() 方法將其與託管資源關聯。該方法如下:

         public void setManagedResource(Object managedResource, String managedResourceType) ;

        managedResourceType 的值可以爲 ObjectReference、Handle、IOR、EJBHandle 或 RMIReference,但當前只支持 ObjectReference。

ModelMBeanInfoSupport 類

        ModelMBeanInfo 接口的默認實現。該類的構造函數如下:

        public ModelMBeanInfoSupport(String className, String description, ModelMBeanAttributeInfo[] attributes, ModelMBeanConstructorInfo[] constructors, ModelMBeanOperationInfo[] operations, ModelMBeanNotificationInfo[] notifications);

        我們接下來介紹參數中出現的幾個類。

ModelMBeanAttributeInfo 類

        模型 MBean 的屬性信息。可以通過如下構造函數構造:

        public ModelMBeanAttributeInfo(String name, String type, String description, boolean isReadable, boolean isWritable, boolean isIs, Descriptor descriptor);

ModelMBeanConstructorInfo 類

ModelMBeanOperationInfo 類

        構造函數如下:

        public ModelMBeanOperationInfo(String name, String description, MBeanParameterInfo[] signature, String type, int impact, Descriptor descriptor);

ModelMBeanNotificationInfo 類

6.2 模型 MBean 示例

        我們需要使用模型 MBean 管理如下所示的 Car 對象:

package test;

public class Car implements CarMBean{
	private String color = "red";
	
	public String getColor(){
		return color;
	}
	public void setColor(String color){
		this.color = color;
	}
	public void drive(){
		System.out.println("Baby you can drive my car.");
	}
}

        對於模型 MBean,不需要像使用標準 MBean 那樣自己編寫接口並使 Car 繼承該接口,而只需實例化 RequiredMBean 類即可。如下的 ModelAgent 類用來創建 ModelMbean 用於管理 Car 對象。

package test;

import javax.management.Attribute;
import javax.management.Descriptor;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.modelmbean.ModelMBean;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.modelmbean.RequiredModelMBean;

public class ModelAgent {
	private String MANAGED_CLASS_NAME = "test.Car";
	private MBeanServer mBeanServer = null;
	
	public ModelAgent(){
		mBeanServer = MBeanServerFactory.createMBeanServer();
	}
	
	public MBeanServer getMBeanServer(){
		return mBeanServer;
	}
	
	private ObjectName createObjectName(String name){
		ObjectName objectName = null;
		try{
			objectName = new ObjectName(name);
		}catch(MalformedObjectNameException e){
			e.printStackTrace();
		}
		return objectName;
	}
	
	private ModelMBean createMBean(ObjectName objectName, String mbeanName){
		ModelMBeanInfo mBeanInfo = createModelMBeanInfo(objectName, mbeanName);
		RequiredModelMBean modelMBean = null;
		try{
			modelMBean = new RequiredModelMBean(mBeanInfo);
		}catch(Exception e){
			e.printStackTrace();
		}
		return modelMBean;
	}
	
	private ModelMBeanInfo createModelMBeanInfo(ObjectName inMbeanObjectName, String inMbeanName){
		ModelMBeanInfo mBeanInfo = null;
		ModelMBeanAttributeInfo[] attributes = new ModelMBeanAttributeInfo[1];
		ModelMBeanOperationInfo[] operations = new ModelMBeanOperationInfo[3];
		try{
			attributes[0] = new ModelMBeanAttributeInfo("Color", "java.lang.String", "the color.", true, true, false, null);
			operations[0] = new ModelMBeanOperationInfo("drive", "the drive method", null, "void", MBeanOperationInfo.ACTION, null);
			operations[1] = new ModelMBeanOperationInfo("getColor", "get color attribute", null, "java.lang.String", MBeanOperationInfo.ACTION, null);
			Descriptor setColorDesc = new DescriptorSupport(new String[]{
					"name=setColor", "descriptorType=operation", "class="+MANAGED_CLASS_NAME, "role=operation"
			});
			MBeanParameterInfo[] setColorParams = new MBeanParameterInfo[]{
				(new MBeanParameterInfo("new color", "java.lang.String", "new Color value"))	
			};
			operations[2] = new ModelMBeanOperationInfo("setColor", "set Color attribute", setColorParams, "void", MBeanOperationInfo.ACTION, setColorDesc);
			mBeanInfo = new ModelMBeanInfoSupport(MANAGED_CLASS_NAME, null, attributes, null, operations, null);
		}catch(Exception e){
			e.printStackTrace();
		}
		return mBeanInfo;
	}
	
	public static void main(String[] args){
		ModelAgent agent = new ModelAgent();
		MBeanServer mBeanServer = agent.getMBeanServer();
		Car car = new Car();
		String domain = mBeanServer.getDefaultDomain();
		ObjectName objectName = agent.createObjectName(domain+":type=MyCar");
		String mBeanName = "myBean";
		ModelMBean modelMBean = agent.createMBean(objectName, mBeanName);
		try{
			//associate the Model MBean with our managed object
			modelMBean.setManagedResource(car, "ObjectReference");
			//register the model MBean to MBeanServer.
			mBeanServer.registerMBean(modelMBean, objectName);
		}catch(Exception e){}
		
		try{
			Attribute attribute = new Attribute("Color", "green");
			mBeanServer.setAttribute(objectName, attribute);
			String color = (String)mBeanServer.getAttribute(objectName, "Color");
			System.out.println("Color:" + color);
			
			attribute = new Attribute("Color", "blueeee");
			mBeanServer.setAttribute(objectName, attribute);
			color = (String)mBeanServer.getAttribute(objectName, "Color");
			System.out.println("Color:" + color);
			
			mBeanServer.invoke(objectName, "drive", null, null);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}


7. Apache 的 Commons Modeler 模型 MBean 庫

        使用 Apache 的 Modeler 庫創建 Model MBean 的最大幫助是,我們不需要再寫複雜的代碼來創建 ModelMBeanInfo 對象了。只需要一個 MBean 描述符來對模型 MBean 進行描述,就可以輕鬆的創建 Model MBean。

1. mbean descriptor (MBean 描述符)

        我們先看一個 MBean 描述符的例子:

<mbean name="StandardServer" 
  className="org.apache.catalina.mbeans.StandardServerMBean" 
  description="Standard Server Component"
  domain="Catalina" 
  group="Server" 
  type="org.apache.catalina.core.StandardServer">

  <attribute name="debug"
    description="The debugging detail level for this component"
    type="int"/>
  <attribute name="managedResource"
    description="The managed resource this MBean is associated with"
    type="java.lang.Object"/>
  <attribute name="port"
    description="TCP port for shutdown message"
    type="int"/>
  <attribute name="shutdown"
    description="Shutdown password"
    type="java.lang.String"/>
  <operation name="store"
    description="Save current state to server.xml"
    impact="ACTION"
    returnType="void">
  </operation>
</mbean>

        上面所示代碼生命了一個模型 MBean。這個 MBean 有以下特點:

        1) 它的唯一標識是 StandardServer。

        2) 該 MBean 是 StandardServerMBean 的一個對象。

        3) 它負責管理的對象是 org.apache.catalina.core.StandardServer 類的實例。

        4) domain 屬性是 Catalina; group 屬性石 Server

        5) 這個 MBean 有四個暴露屬性: debug、managedResource、port、shutdown,另外還有一個暴露方法 store().


2. Tomcat Modeler 常用類介紹

Registry 類

ManagedBean 類

        對 Model MBean 的描述。

BaseModelMBean 類

        實現了 ModelMBean 接口。使用這個類就不需要 RequiredModelMBean 類了。另外,該類有一個比較有用的字段 resource。resource 字段標識該模型 MBean 管理的資源。如果在 MBean 描述符的聲明中沒有指定 className,則默認使用 BaseModelMBean。

3. 使用 Tomcat Model 實現模型 MBean

        我們仍然使用對 Car 類進行管理的例子。

package test;

public class Car{
	private String color = "red";
	
	public Car(){
		System.out.println("Car constructor");
	}

	public String getColor(){
		return color;
	}
	public void setColor(String color){
		this.color = color;
	}
	public void drive(){
		System.out.println("Baby you can drive my car.");
	}
}

我們的 MBean 描述符文件 mbeans-descriptors.xml 文件如下:

<?xml version="1.0"?>
<!DOCTYPE mbeans-descriptors PUBLIC
  "-//Apache Software Foundation//DTD Model MBeans Configuration File" 
  "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">

<mbeans-descriptors>
  <mbean name="myBean"
    className="javax.management.modelmbean.RequiredModelMBean"
    description="The ModelMBean that manages our Car object"
    type="test.Car">
  
    <attribute name="Color"
      description="The car color"
      type="java.lang.String"/>
    <operation name="drive"
      description="drive method"
      impact="ACTION"
      returnType="void">
      <parameter name="driver" description="the driver parameter" type="java.lang.String"/>
    </operation>
  </mbean>
</mbeans-descriptors>

        代理類 ModelAgent.java 如下所示:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章