前面已经说了,在Distributed Layer,为了让JMXAgent能和外部客户端通信,有两种连接方式,一种是adapter,一种是connector.对于adapter,这种方式我们在上一节的HelloWorld例子已经看到了,只要在服务端开一个Adapter服务并且注册到MBeanServer就可以了,对于connector的方式,则必须在客户端和服务端都有一个组件,我们这里就演示这个例子:
比如我们要让客户端以编程的方式访问JMXAgent,那么我们可能需要用RMIConnector ,为了也能让用户可以通过浏览器来访问操作JMXAgent,所以我们的Agent里面既创建了一个HTMLAdapter的服务,也创建了一个RMIConnector的服务,分别封装在startHTMLAdapter()和startRMIConnector()方法中:
- /*
- * This file is confidential by Charles.Wang
- * Copyright belongs to Charles.wang
- * You can make contact with Charles.Wang ([email protected])
- */
- package com.charles.jmxagent;
- import javax.management.MBeanServer;
- import javax.management.MBeanServerFactory;
- import javax.management.ObjectName;
- import javax.management.remote.rmi.RMIConnectorServer;
- import com.charles.util.ExceptionUtil;
- import com.sun.jdmk.comm.HtmlAdaptorServer;
- import com.sun.jdmk.comm.RmiConnectorServer;
- /**
- * @author charles.wang (Senior Software Engineer)
- * mailto: [email protected]
- * @created 2011-12-31����10:59:05
- * Description: 对于一个Agent,它主要有2个责任,一是创建MBeanServer, 另外一个是提供对外的连接
- * 对于对外提供连接:我们最常用的是HTMLAdaptor,这样仅仅依靠浏览器就可以和Agent交互
- * 其实我们也可以提供RMI Connector 等来让其他应用通过API来和Agent交互
- */
- public class JMXBookAgent {
- private MBeanServer server = null;
- public JMXBookAgent(){
- //创建 MBeanServer,并且使用 Domain名叫”JMXBookAgent“
- System.out.println("Create the MBeanServer.");
- server= MBeanServerFactory.createMBeanServer("JMXBookAgent");
- //为了以两种不同的方式和外界交互,我们这里启动了2个服务
- //一个是HTMLAdaptor,它允许管理程序HTTP协议来和Agent交互,只需要一个浏览器即可
- //另外一个是RMIConnector,它允许管理程序通过RMI来和Agent交互
- //这两个都位于distributed layer
- startHTMLAdapter();
- startRMIConnector();
- }
- //创建一个HTMLAdaptor并且绑定到9092端口,最终把这个htmlAdaptor启动起来
- protected void startHTMLAdapter(){
- HtmlAdaptorServer adapter = new HtmlAdaptorServer();
- ObjectName adapterName = null;
- try{
- adapter.setPort(9092);
- //复习下:这ObjectName还是必须由一个Domain名和多个描述属性组成
- adapterName = new ObjectName("JMXBookAgent:name=html,port=9092");
- server.registerMBean(adapter, adapterName);
- //启动这个HTMLAdapter服务
- adapter.start();
- }catch (Exception e){
- ExceptionUtil.printException(e);
- System.out.println("Error starting HtmlAdapter for agent");
- }
- }
- //创建一个RMILConnector并且绑定到2099端口,最终把这个rmiConnector启动起来
- //RMIConnector包含2个部分,一个是服务器端,一个是客户端
- //服务器端位于MBeanServer中从而向外界提供对MBeanServer的访问
- //所以我们吧这个connector的服务器端实例注册给MBeanServer,客户端我们不在这里定义
- protected void startRMIConnector(){
- //创建RMIConnector的服务器端的实例
- RmiConnectorServer connector = new RmiConnectorServer();
- ObjectName connectorName = null;
- try{
- //设置RMIConnector的端口号
- connector.setPort(2099);
- //创建RMIConnector的ObjectName
- connectorName = new ObjectName("JMXBookAgent:name=RMIConnector");
- //绑定RMIConnector服务器实例到ObjectName,并且注册到MBeanServer
- server.registerMBean(connector, connectorName);
- //在2099端口上启动RMIConnector服务从而它可以为外界提供基于RMI的对JMXAgent的访问
- //这是一种“编程式"的访问
- connector.start();
- }catch (Exception e){
- ExceptionUtil.printException(e);
- System.out.println("Error starting RMIConnector for agent");
- }
- }
- public static void main (String [] args){
- System.out.println("**********************************");
- System.out.println("Start of JMXBook Agent...");
- System.out.println("Create this Agent...");
- JMXBookAgent agent = new JMXBookAgent();
- System.out.println("Agent is ready for service");
- }
- }
然后我们吧这个JMXAgent启动起来,于是这个JMXAgent就可以对外提供服务了,我们可以从浏览器通过HTMLAdapter来看这个JMXAgent的状态:
为了验证RMIConnector也能提供服务,我们选中name=RMIConnector切换到MBean视图:
所以这里我们可以看到,RMIConnector也可以对外提供访问了,它提供的是编程式的访问。
因为RMIConnector是个connector,所以它不仅有连接器服务端,还应该有连接器客户端,所以我们这里创建一个连接器客户端工厂来创建RMI连接器客户端,这个连接器客户端负责与RMI连接器服务器端创建连接:
- /*
- * This file is confidential by Charles.Wang
- * Copyright belongs to Charles.wang
- * You can make contact with Charles.Wang ([email protected])
- */
- package com.charles.client;
- import com.charles.util.ExceptionUtil;
- import com.sun.jdmk.comm.RmiConnectorAddress;
- import com.sun.jdmk.comm.RmiConnectorClient;
- /**
- * @author charles.wang (Senior Software Engineer)
- * mailto: [email protected]
- * @created 2012-1-1����7:50:06
- * Description: 因为RMI使用的是Connector而不是Adapter的形式提供服务的,所以除了在服务端,也就是在
- * Distributed Layer中提供启动RMIAdapter服务以外,也要构建客户端,所以这个类就是用于创建连接到JMXAgent的客户端
- * 同样,我们用的是sun的RI实现,所以用的com.sun.jdmk.comm.RmiConnectorClient;
- */
- public class RMIClientFactory {
- //这个静态方法是工程类的方法,它用于创建一个连接到JMXAgent的RMI客户端,
- public static RmiConnectorClient getClient(){
- //先创建一个RMI连接器客户端对象
- RmiConnectorClient client = new RmiConnectorClient();
- //因为在Distributed Layer,我们已经有RMIConnector服务端,并且开放了端口2099,
- //所以我们创建一个服务端的地址对象,用来定位RMIConnector的服务器端
- RmiConnectorAddress address = new RmiConnectorAddress();
- address.setPort(2099);
- System.out.println("Address Type: "+address.getConnectorType());
- System.out.println("Address Port: "+address.getPort());
- System.out.println("Address Host: "+address.getHost());
- System.out.println("Address Name: "+address.getName());
- try{
- //让客户端连接到JMXAgent
- client.connect(address);
- }catch (Exception e){
- ExceptionUtil.printException(e);
- }
- //如果没有异常抛出,泽说明连接成功,于是返回创建的这个客户端对象
- return client;
- }
- }
最后,我们要创建真正的客户端应用了,这个客户端要和RMI连接器客户端打交道,进而间接的访问RMI连接器服务端,最终访问JMXAgent(这一切都是编程式的访问):
- /*
- * This file is confidential by Charles.Wang
- * Copyright belongs to Charles.wang
- * You can make contact with Charles.Wang ([email protected])
- */
- package com.charles.client;
- import javax.management.ObjectName;
- import com.sun.jdmk.comm.RmiConnectorClient;
- /**
- * @author charles.wang (Senior Software Engineer)
- * mailto: [email protected]
- * @created 2012-1-1����8:21:56
- * Description: 因为RMIConnector存在的意义是通过编程的方式来让客户端访问JMXAgent从而获得信息的
- * 所以这个类就是一个真正的客户端,从而可以通过RMIConnector,通过编程的方式获得JMXAgent的信息
- */
- public class HelloWorldSetup {
- /**
- * Function:
- * @author charles.wang
- * @param args
- */
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- HelloWorldSetup setup = new HelloWorldSetup();
- }
- /**
- * 这个构造函数用于访问JMXAgent,通过RMIConnector
- * 所以它必须先创建一个RMIConnectorClient对象,然后让它来调用JMXAgent中的MBean的方法
- */
- public HelloWorldSetup(){
- try{
- //创建一个RMIConnector客户端对象,通过它来和JMXAgent交互
- RmiConnectorClient client = RMIClientFactory.getClient();
- //创建一个ObjectName,
- ObjectName hwName = new ObjectName("JMXBookAgent:name=helloWorldcharles");
- //让RMI客户端创建MBean的实例,并且关联懂啊这个ObjectName上
- client.createMBean("com.charles.jmx.HelloWorld", hwName);
- //RMI客户端通过ObjectName来调用MBean上的业务方法
- client.invoke(hwName, "printGreeting", null, null);
- }catch (Exception e){
- e.printStackTrace();
- }
- }
- }
我们在代码的46行可以看到,这个真正的客户端应用会“委托”RMI连接器客户端,让它去调用JMXAgent中指定MBean的业务方法printGreeting(),因为我们在前面已经吧JMXAgent启动起来了,所以这里只要启动这个客户端,就可以看到printGreeting()的调用结果了: