前面已经说了,在Distributed Layer,为了让JMXAgent能和外部客户端通信,有两种连接方式,一种是adapter,一种是connector.对于adapter,这种方式我们在上一节的HelloWorld例子已经看到了,只要在服务端开一个Adapter服务并且注册到MBeanServer就可以了,对于connector的方式,则必须在客户端和服务端都有一个组件,我们这里就演示这个例子:

 

比如我们要让客户端以编程的方式访问JMXAgent,那么我们可能需要用RMIConnector ,为了也能让用户可以通过浏览器来访问操作JMXAgent,所以我们的Agent里面既创建了一个HTMLAdapter的服务,也创建了一个RMIConnector的服务,分别封装在startHTMLAdapter()和startRMIConnector()方法中:

   
   
   
   
  1. /* 
  2.  *  This file is confidential by Charles.Wang 
  3.  *  Copyright belongs to Charles.wang 
  4.  *  You can make contact with Charles.Wang ([email protected]) 
  5.  */ 
  6. package com.charles.jmxagent; 
  7.  
  8. import javax.management.MBeanServer; 
  9. import javax.management.MBeanServerFactory; 
  10. import javax.management.ObjectName; 
  11. import javax.management.remote.rmi.RMIConnectorServer; 
  12.  
  13.  
  14.  
  15. import com.charles.util.ExceptionUtil; 
  16. import com.sun.jdmk.comm.HtmlAdaptorServer; 
  17. import com.sun.jdmk.comm.RmiConnectorServer; 
  18.  
  19. /** 
  20.  * @author        charles.wang (Senior Software Engineer) 
  21.  *                mailto: [email protected] 
  22.  * @created       2011-12-31����10:59:05 
  23.  
  24.  * Description: 对于一个Agent,它主要有2个责任,一是创建MBeanServer, 另外一个是提供对外的连接 
  25.  * 对于对外提供连接:我们最常用的是HTMLAdaptor,这样仅仅依靠浏览器就可以和Agent交互 
  26.  * 其实我们也可以提供RMI Connector 等来让其他应用通过API来和Agent交互 
  27.  */ 
  28. public class JMXBookAgent { 
  29.      
  30.     private MBeanServer server = null
  31.      
  32.     public JMXBookAgent(){ 
  33.          
  34.         //创建 MBeanServer,并且使用 Domain名叫”JMXBookAgent“ 
  35.         System.out.println("Create the MBeanServer."); 
  36.         server= MBeanServerFactory.createMBeanServer("JMXBookAgent"); 
  37.          
  38.         //为了以两种不同的方式和外界交互,我们这里启动了2个服务 
  39.         //一个是HTMLAdaptor,它允许管理程序HTTP协议来和Agent交互,只需要一个浏览器即可 
  40.         //另外一个是RMIConnector,它允许管理程序通过RMI来和Agent交互 
  41.         //这两个都位于distributed layer 
  42.         startHTMLAdapter(); 
  43.         startRMIConnector(); 
  44.     } 
  45.      
  46.     //创建一个HTMLAdaptor并且绑定到9092端口,最终把这个htmlAdaptor启动起来 
  47.     protected void startHTMLAdapter(){ 
  48.          
  49.         HtmlAdaptorServer adapter = new HtmlAdaptorServer(); 
  50.         ObjectName adapterName = null
  51.          
  52.         try
  53.              
  54.             adapter.setPort(9092); 
  55.             //复习下:这ObjectName还是必须由一个Domain名和多个描述属性组成 
  56.             adapterName = new ObjectName("JMXBookAgent:name=html,port=9092"); 
  57.             server.registerMBean(adapter, adapterName); 
  58.             //启动这个HTMLAdapter服务 
  59.             adapter.start(); 
  60.              
  61.         }catch (Exception e){ 
  62.             ExceptionUtil.printException(e); 
  63.             System.out.println("Error starting HtmlAdapter for agent"); 
  64.         } 
  65.     } 
  66.      
  67.     //创建一个RMILConnector并且绑定到2099端口,最终把这个rmiConnector启动起来 
  68.     //RMIConnector包含2个部分,一个是服务器端,一个是客户端 
  69.     //服务器端位于MBeanServer中从而向外界提供对MBeanServer的访问 
  70.     //所以我们吧这个connector的服务器端实例注册给MBeanServer,客户端我们不在这里定义 
  71.     protected void startRMIConnector(){ 
  72.         //创建RMIConnector的服务器端的实例 
  73.         RmiConnectorServer connector = new RmiConnectorServer(); 
  74.         ObjectName connectorName = null
  75.         try
  76.             //设置RMIConnector的端口号 
  77.             connector.setPort(2099); 
  78.              
  79.             //创建RMIConnector的ObjectName 
  80.             connectorName = new ObjectName("JMXBookAgent:name=RMIConnector"); 
  81.              
  82.             //绑定RMIConnector服务器实例到ObjectName,并且注册到MBeanServer 
  83.             server.registerMBean(connector, connectorName); 
  84.              
  85.             //在2099端口上启动RMIConnector服务从而它可以为外界提供基于RMI的对JMXAgent的访问 
  86.             //这是一种“编程式"的访问 
  87.             connector.start(); 
  88.         }catch (Exception e){ 
  89.             ExceptionUtil.printException(e); 
  90.             System.out.println("Error starting RMIConnector for agent"); 
  91.         } 
  92.          
  93.     } 
  94.      
  95.     public static void main (String [] args){ 
  96.         System.out.println("**********************************"); 
  97.         System.out.println("Start of JMXBook Agent..."); 
  98.         System.out.println("Create this Agent..."); 
  99.         JMXBookAgent agent = new JMXBookAgent(); 
  100.         System.out.println("Agent is ready for service"); 
  101.     } 

 

然后我们吧这个JMXAgent启动起来,于是这个JMXAgent就可以对外提供服务了,我们可以从浏览器通过HTMLAdapter来看这个JMXAgent的状态:

(JMX 读书笔记) 用RMIConnector 编程式的访问JMXAgent_第1张图片

为了验证RMIConnector也能提供服务,我们选中name=RMIConnector切换到MBean视图:

 

(JMX 读书笔记) 用RMIConnector 编程式的访问JMXAgent_第2张图片

所以这里我们可以看到,RMIConnector也可以对外提供访问了,它提供的是编程式的访问。

 

因为RMIConnector是个connector,所以它不仅有连接器服务端,还应该有连接器客户端,所以我们这里创建一个连接器客户端工厂来创建RMI连接器客户端,这个连接器客户端负责与RMI连接器服务器端创建连接:

   
   
   
   
  1. /* 
  2.  *  This file is confidential by Charles.Wang 
  3.  *  Copyright belongs to Charles.wang 
  4.  *  You can make contact with Charles.Wang ([email protected]) 
  5.  */ 
  6. package com.charles.client; 
  7.  
  8. import com.charles.util.ExceptionUtil; 
  9. import com.sun.jdmk.comm.RmiConnectorAddress; 
  10. import com.sun.jdmk.comm.RmiConnectorClient; 
  11.  
  12. /** 
  13.  * @author        charles.wang (Senior Software Engineer) 
  14.  *                mailto: [email protected] 
  15.  * @created       2012-1-1����7:50:06 
  16.  
  17.  * Description: 因为RMI使用的是Connector而不是Adapter的形式提供服务的,所以除了在服务端,也就是在 
  18.  * Distributed Layer中提供启动RMIAdapter服务以外,也要构建客户端,所以这个类就是用于创建连接到JMXAgent的客户端 
  19.  * 同样,我们用的是sun的RI实现,所以用的com.sun.jdmk.comm.RmiConnectorClient; 
  20.  */ 
  21. public class RMIClientFactory { 
  22.      
  23.     //这个静态方法是工程类的方法,它用于创建一个连接到JMXAgent的RMI客户端, 
  24.     public static RmiConnectorClient getClient(){ 
  25.          
  26.         //先创建一个RMI连接器客户端对象 
  27.         RmiConnectorClient client = new RmiConnectorClient(); 
  28.          
  29.          
  30.         //因为在Distributed Layer,我们已经有RMIConnector服务端,并且开放了端口2099, 
  31.         //所以我们创建一个服务端的地址对象,用来定位RMIConnector的服务器端 
  32.         RmiConnectorAddress address = new RmiConnectorAddress(); 
  33.         address.setPort(2099); 
  34.         System.out.println("Address Type: "+address.getConnectorType()); 
  35.         System.out.println("Address Port: "+address.getPort()); 
  36.         System.out.println("Address Host: "+address.getHost()); 
  37.         System.out.println("Address Name: "+address.getName()); 
  38.          
  39.         try
  40.             //让客户端连接到JMXAgent 
  41.             client.connect(address); 
  42.         }catch (Exception e){ 
  43.             ExceptionUtil.printException(e); 
  44.         } 
  45.          
  46.         //如果没有异常抛出,泽说明连接成功,于是返回创建的这个客户端对象 
  47.         return client; 
  48.     } 
  49.  

 

最后,我们要创建真正的客户端应用了,这个客户端要和RMI连接器客户端打交道,进而间接的访问RMI连接器服务端,最终访问JMXAgent(这一切都是编程式的访问):

   
   
   
   
  1. /* 
  2.  *  This file is confidential by Charles.Wang 
  3.  *  Copyright belongs to Charles.wang 
  4.  *  You can make contact with Charles.Wang ([email protected]) 
  5.  */ 
  6. package com.charles.client; 
  7.  
  8. import javax.management.ObjectName; 
  9.  
  10. import com.sun.jdmk.comm.RmiConnectorClient; 
  11.  
  12. /** 
  13.  * @author        charles.wang (Senior Software Engineer) 
  14.  *                mailto: [email protected] 
  15.  * @created       2012-1-1����8:21:56 
  16.  
  17.  * Description: 因为RMIConnector存在的意义是通过编程的方式来让客户端访问JMXAgent从而获得信息的 
  18.  * 所以这个类就是一个真正的客户端,从而可以通过RMIConnector,通过编程的方式获得JMXAgent的信息 
  19.  */ 
  20. public class HelloWorldSetup { 
  21.  
  22.     /** 
  23.      * Function: 
  24.      * @author charles.wang 
  25.      * @param args 
  26.      */ 
  27.     public static void main(String[] args) { 
  28.         // TODO Auto-generated method stub 
  29.         HelloWorldSetup setup = new HelloWorldSetup(); 
  30.     } 
  31.      
  32.      
  33.     /** 
  34.      *  这个构造函数用于访问JMXAgent,通过RMIConnector 
  35.      *  所以它必须先创建一个RMIConnectorClient对象,然后让它来调用JMXAgent中的MBean的方法 
  36.      */ 
  37.     public HelloWorldSetup(){ 
  38.          
  39.         try
  40.             //创建一个RMIConnector客户端对象,通过它来和JMXAgent交互 
  41.             RmiConnectorClient client = RMIClientFactory.getClient(); 
  42.             //创建一个ObjectName, 
  43.             ObjectName hwName = new ObjectName("JMXBookAgent:name=helloWorldcharles"); 
  44.             //让RMI客户端创建MBean的实例,并且关联懂啊这个ObjectName上 
  45.             client.createMBean("com.charles.jmx.HelloWorld", hwName); 
  46.             //RMI客户端通过ObjectName来调用MBean上的业务方法 
  47.             client.invoke(hwName, "printGreeting"nullnull); 
  48.         }catch (Exception e){ 
  49.             e.printStackTrace(); 
  50.         } 
  51.     } 
  52.      
  53.      
  54.  

我们在代码的46行可以看到,这个真正的客户端应用会“委托”RMI连接器客户端,让它去调用JMXAgent中指定MBean的业务方法printGreeting(),因为我们在前面已经吧JMXAgent启动起来了,所以这里只要启动这个客户端,就可以看到printGreeting()的调用结果了: