JMX(二)----connectors


     继续之前的,之前介绍了MBean server (http://90haofang-163-com.iteye.com/blog/1901416),这次主要简述如果使用JMX技术管理MBean,执行远程操作。通过RMI 作为connectors访问MBeans。这块需要实现服务端和客户端。

首先编写服务端:

1.创建MBean接口类SimpleStandardMBean

 

package git.git.tudou.manage.jmx.test.connectors;

/**
 * Date: 13-7-9
 * Time: 下午4:06
 */
public interface SimpleStandardMBean {
    //获取当前state 值
    public String getState();
    //修改state
    public void setState(String state);
    //获取状态改变次数
    public int getNuberChanges();
    //重置state和计数器 为初始值
    public void reset();

}
 然后编写MBean实现类SimpleStandard,名字必须是MBean的前缀,不然创建的MBean会出现问题。

 

package git.git.tudou.manage.jmx.test.connectors;

import javax.management.AttributeChangeNotification;
import javax.management.NotificationBroadcasterSupport;
import java.util.Date;

/**
 * standard MBean支持notification广播功能
 * Date: 13-7-9
 * Time: 下午4:05
 */
public class SimpleStandard  extends NotificationBroadcasterSupport implements SimpleStandardMBean{
    private  String state = "initial stae";
    private int nuberChanges=0;
    private int nbReset = 0;
    public String getState() {
        return this.state;
    }

    public void setState(String state) {
         this.state =state;
         //状态次数加1
         this.nuberChanges++;
    }

    public int getNuberChanges() {
        return this.nuberChanges;
    }
    public int getNbReset(){
        return this.nbReset;
    }

    public void reset() {
        state = "init state" ;
        this.nuberChanges = 0;
        nbReset++;
        /**
         * 属性变更通知
         * 参数说明
         * p1:指示通知的来源 在这里就是Hello MBean,用this替代
         * p2: 通知消息的序列号
         * p3:时间戳
         * p4:通知的内容
         * p5:变更的属性名
         * p6:变更属性的数据类型
         * p7: 属性的原值
         * p8:属性的新值
       */
        AttributeChangeNotification acn = new AttributeChangeNotification(
                this,nbReset,new Date().getTime(),"状态改变次数重置 ,state重置","Nbchanges","int",nuberChanges,0);
        sendNotification(acn);
    }
}
 该类继承了NotificationBroadcasterSupport ,实现通知功能在reset方法中发送了一个通知,说明nbchanges被重置,后面在客户端实现一个监听器,来接受通知。
服务端类Server
package git.git.tudou.manage.jmx.test.connectors;


import javax.management.*;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.rmi.registry.LocateRegistry;
import java.util.Scanner;

/**
 * MBean server
 * encode gbk
 * Date: 13-7-9
 * Time: 下午2:57
 */
public class Server {
    public static void main(String args[]){
        try{
            Scanner sc = new Scanner(System.in);
            LocateRegistry.createRegistry(9999);  //必须加上这句 不然就报错了 
           //创建一个MBean server
            MBeanServer mBeanServer = MBeanServerFactory.createMBeanServer();
            //停顿一下
            sc.nextInt();
            //获得mBeanServer 默认域
            String domain = mBeanServer.getDefaultDomain();
            System.out.println("mBeanServer defualt domain:"+domain);
            sc.nextInt();
            //创建一个并且注册一个 SimpleStandard MBean
            String mbeanClassName = "git.git.tudou.manage.jmx.test.connectors.SimpleStandard";
            String mbeanObjectNameStr = domain+":type="+mbeanClassName+",name=1";
            //在MBean server创建一个bean
            ObjectName mBeanObjectName =  createSimpleMBean(mBeanServer,mbeanClassName,mbeanObjectNameStr);
            //输出MBean info
            printMBeanInfo(mBeanServer,mBeanObjectName,mbeanObjectNameStr);
            sc.nextInt();
            //通过MBean server管理MBean 类
            manageSimpleMBean(mBeanServer,mBeanObjectName,mbeanClassName);
            sc.nextInt();
            //创建RMI server 工程应用程序调用
            JMXServiceURL url = new JMXServiceURL(//url 绑定9999端口,这个可以自定义
            		      "service:jmx:rmi:///jndi/rmi://10.12.145.22:9999/server");
            //通过JMXConnectorServerFactory工厂 创建一个RMI连接实例
            JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url,null,mBeanServer);
            //启动RMI连接服务器
            connectorServer.start();
            System.out.println("RMI 服务已经启动..等待接受请求.");
            sc.nextInt();
            System.out.println("RMI服务关闭..");
            connectorServer.stop();
        }catch (Exception e){
            System.out.println("创建mbean server 异常"+e);
        }
    }
    //管理simpleMBean类
    public static void manageSimpleMBean(MBeanServer mbs,ObjectName mbeanObjectName,String mbeanClassName){
        try{
            //打印最开始的属性值
            printSimpleAttributes(mbs,mbeanObjectName);
            System.out.println("--------------------------------");
            System.out.println("修改state值为new state");
            Attribute attribute = new Attribute("State","new state");
            mbs.setAttribute(mbeanObjectName,attribute);
            System.out.println("--------------------------------");
            System.out.println("修改后的属性值:");
            printSimpleAttributes(mbs,mbeanObjectName);
            //调用reset方法
            mbs.invoke(mbeanObjectName,"reset",null,null);
            System.out.println("重置后所有属性值:");
            printSimpleAttributes(mbs,mbeanObjectName);

        }catch (Exception e){
            System.out.println("变更Simple Bean异常"+e);
        }

    }

    /**
     * 答应出MBean 的属性
     * @param mbs
     * @param mbeanObjectName
     */
    public static  void printSimpleAttributes(MBeanServer mbs,ObjectName mbeanObjectName){
        System.out.println("属性集合:");
        try{
            System.out.println("--------------------------------");
            System.out.println("SimpleMBean 属性值:");
            String state =(String)mbs.getAttribute(mbeanObjectName,"State");
            System.out.println("\tstate:"+state);
            int nuberChanges = (Integer)mbs.getAttribute(mbeanObjectName,"NuberChanges");
            System.out.println("\tnuberChanges:"+nuberChanges);
        }catch (Exception e){
            System.out.println("获取mbean属性异常"+e);
        }

    }
    /**
     * 打印MBean 信息
     * @param mbs
     * @param mbeanObjectName
     * @param mbeanClassName
     */
    public static void printMBeanInfo(MBeanServer mbs,ObjectName mbeanObjectName,String mbeanClassName){
        MBeanInfo info = null;
        try{
           info = mbs.getMBeanInfo(mbeanObjectName);
        }catch (Exception e){
            e.printStackTrace();
            System.out.println("获取"+mbeanClassName+"MBeanInfo 失败");
        }
        System.out.println("-------------------------------------------");
        System.out.println("类名:\t"+info.getClassName());
        System.out.println("类描述:\t"+info.getDescription());
        System.out.println("-------------------------------------------");
        System.out.println("属性:");
        MBeanAttributeInfo[] attributeInfos = info.getAttributes();
        for(MBeanAttributeInfo ainfo:attributeInfos){
            System.out.println("属性名:\t"+ainfo.getName());
            System.out.println("属性描述:\t"+ainfo.getDescription());
            System.out.println("属性数据类型\t"+ainfo.getType());
            System.out.println("属性是否可读\t"+ainfo.isReadable());
            System.out.println("属性是否可写\t"+ainfo.isWritable());
        }
        System.out.println("-------------------------------------------");
        System.out.println("构造方法:");
        MBeanConstructorInfo[] constructorInfos = info.getConstructors();
        for(MBeanConstructorInfo cinfo:constructorInfos){
            System.out.println("方法名:\t"+cinfo.getName());
            System.out.println("方法描述:"+cinfo.getDescription());
            System.out.println("参数个数:\t"+cinfo.getSignature().length);
        }
        System.out.println("-------------------------------------------");
        System.out.println("方法:");
        MBeanOperationInfo[]  operationInfos= info.getOperations();
        for(MBeanConstructorInfo oinfo:constructorInfos){
            System.out.println("方法名:\t"+oinfo.getName());
            System.out.println("方法描述:"+oinfo.getDescription());
            System.out.println("参数个数:\t"+oinfo.getSignature().length);
        }
        System.out.println("-------------------------------------------");
        System.out.println("通知:");
        MBeanNotificationInfo[] notificationInfos = info.getNotifications();
        for(MBeanNotificationInfo ninfo:notificationInfos){
            System.out.println("通知名:\t"+ninfo.getName());
            System.out.println("通知描述:"+ninfo.getDescription());
            String notificationType[] = ninfo.getNotifTypes();
            for(int i=0;i<notificationType.length;i++){
                System.out.println("type \t"+notificationType[i]);
            }
        }

    }
    public  static ObjectName createSimpleMBean(MBeanServer mbs,String mbeanClassName,String mbeanObjectNameStr){
        try{
            System.out.println("创建一个MBean "+mbeanClassName+"并在server 注册");
            ObjectName mbeanObjectName = ObjectName.getInstance(mbeanObjectNameStr);
            //MBean server创建一个bean
            mbs.createMBean(mbeanClassName,mbeanObjectName);
            return mbeanObjectName;
        }catch (Exception e){
            e.printStackTrace();
            System.exit(1);
        }
        return  null;
    }
}
 这里类首先创建一个MBserver.然后通过RMI发布出去。供远程应用程序调用,要注意的是
 LocateRegistry.createRegistry(9999); //这个很重要。不然直接无发绑定端口号,10.12.145.22是我的server运行的ip地址,应该替换为自己的server运行的ip地址。
创建mbean server 异常java.io.IOException: Cannot bind to URL [rmi://10.12.145.22:9999/server]: javax.naming.ServiceUnavailableException [Root exception is java.rmi.ConnectException: Connection refused to host: 10.12.145.22; nested exception is: 
	java.net.ConnectException: Connection refused: connect]
Disconnected from the target VM, address: '127.0.0.1:51094', transport: 'socket'
编写好服务端后,不着急写客户端首先可以用jconsole连接下这个服务地址 service:jmx:rmi:///jndi/rmi://10.12.145.22:9999/server 查看MBean,如图
 

 下图是我执行了操作reset,一共执行了2次,所以收到了两个通知,通知的发送定义在SimpleStandardMBean.reset方法中。

 接下自己编写客户端来管理MBean,通过RMI连接到MBserver,首先创建一个客户端监听器ClientListener,用来处理来自MBserver的通知
package git.git.tudou.manage.jmx.test.connectors;

import javax.management.Notification;
import javax.management.NotificationListener;

/**
 * 客户端监听通知监听器
 * Date: 13-7-9
 * Time: 下午6:54
 */
public class ClientListener implements NotificationListener {
    public void handleNotification(Notification notification, Object handback) {
        System.out.println("来自MBean server通知:"+notification.getMessage());
    }
}
ClientListener实现NotificationListener接口,实现handleNotification,用来处理来自客户端的通知。
接下来编写客户端Cient类
package git.git.tudou.manage.jmx.test.connectors;

import javax.management.Attribute;
import javax.management.JMX;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;

/**
 * 创建一个RMI连接客户端
 * Date: 13-7-9
 * Time: 下午6:56
 */
public class Client {
    public static void main(String[] args) {
        try{
            Scanner sc = new Scanner(System.in);
            //通过rmi连接远程MBean
            JMXServiceURL url =  new JMXServiceURL("service:jmx:rmi:///jndi/rmi://10.12.145.22:9999/server");
            //获得远程JMX连接
            JMXConnector jmxConnector = JMXConnectorFactory.connect(url,null);
            ClientListener listener = new ClientListener();
            //获得MBserverConnection
            MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
            sc.nextInt();
            System.out.println("domain:");
            //获Mbean server所有连接
            String domains[] = mBeanServerConnection.getDomains();
            for(int i=0;i<domains.length;i++){
                System.out.println("domains["+i+"]="+domains[i]);
            }
            sc.nextInt();
            String domain=mBeanServerConnection.getDefaultDomain();
            String mbeanObjectNameStr = domain+":type=SimpleStandard,name=2";
            //新建一个ObjectName实例
            ObjectName mbeanObjectName = ObjectName.getInstance(mbeanObjectNameStr);
            //创建一个MBean
            mBeanServerConnection.createMBean("git.git.tudou.manage.jmx.test.connectors.SimpleStandard",mbeanObjectName,null,null);
            sc.nextInt();
            //获取所有的Object名字
            Set names = mBeanServerConnection.queryNames(null, null);
            for (Iterator i= names.iterator();i.hasNext();){
                System.out.println("ObjectName"+(ObjectName)i.next());
            }
            sc.nextInt();
            //管理MBean 首先变更属性
            System.out.println("state:"+(String)mBeanServerConnection.getAttribute(mbeanObjectName,"State"));
            mBeanServerConnection.setAttribute(mbeanObjectName, new Attribute("State", "new state2"));
            System.out.println("修改后 state:"+(String)mBeanServerConnection.getAttribute(mbeanObjectName,"State"));
            //方式二 直接通过MXBean代理
            /**
             * p1 MBean server连接
             * p2  MBean name
             * p3  接口类
             * p4  标记是否是NotificationBroadSupport
             */
            SimpleStandardMBean proxy = JMX.newMXBeanProxy(mBeanServerConnection,mbeanObjectName,SimpleStandardMBean.class,true);
            System.out.println("state 使用proxy:"+proxy.getState());
            //添加Notification监听器
            System.out.println("添加Notification监听器");
            mBeanServerConnection.addNotificationListener(mbeanObjectName,listener,null,null);
            //mBeanServerConnection 调用SimpleStandard reset方法
            mBeanServerConnection.invoke(mbeanObjectName,"reset",null,null);
            // proxy 调用reset方法
            System.out.println("proxy 调用reset方法");
            proxy.reset();
            sc.nextInt();
            Thread.sleep(2000);
            System.out.println("关闭连接。。。。");
            sc.nextInt();
            jmxConnector.close();
        }catch (Exception e){
            System.out.println("连接远程rmi异常,无法获得MBserver 连接"+e);
        }

    }
}
 改客户端类首先连接RMIserver 获得一个连接器,从连接器获得MBean server连接mBeanServerConnection,然后通过这个连接来管理远程MBean,可以通过它改变MBean属性,调用其方法
代码里面用两种方式获得MBean,一种是直接通过MBean创建,一种是proxy模式。通过MBean接口实例,调用MBean方法或者修改它的属性。
然后启动服务端,控制台输出:
1
mBeanServer defualt domain:DefaultDomain
1
创建一个MBean git.git.tudou.manage.jmx.test.connectors.SimpleStandard并在server 注册
-------------------------------------------
类名:	git.git.tudou.manage.jmx.test.connectors.SimpleStandard
类描述:	Information on the management interface of the MBean
-------------------------------------------
属性:
属性名:	State
属性描述:	Attribute exposed for management
属性数据类型	java.lang.String
属性是否可读	true
属性是否可写	true
属性名:	NuberChanges
属性描述:	Attribute exposed for management
属性数据类型	int
属性是否可读	true
属性是否可写	false
-------------------------------------------
构造方法:
方法名:	git.git.tudou.manage.jmx.test.connectors.SimpleStandard
方法描述:Public constructor of the MBean
参数个数:	0
-------------------------------------------
方法:
方法名:	git.git.tudou.manage.jmx.test.connectors.SimpleStandard
方法描述:Public constructor of the MBean
参数个数:	0
-------------------------------------------
通知:
1
属性集合:
--------------------------------
SimpleMBean 属性值:
	state:initial stae
	nuberChanges:0
--------------------------------
修改state值为new state
--------------------------------
修改后的属性值:
属性集合:
--------------------------------
SimpleMBean 属性值:
	state:new state
	nuberChanges:1
重置后所有属性值:
属性集合:
--------------------------------
SimpleMBean 属性值:
	state:init state
	nuberChanges:0
1
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
RMI 服务已经启动..等待接受请求.
 执行客户端main方法,输出:
1
domain:
domains[0]=JMImplementation
domains[1]=DefaultDomain
1
1
ObjectNameDefaultDomain:type=SimpleStandard,name=2
ObjectNameDefaultDomain:type=git.git.tudou.manage.jmx.test.connectors.SimpleStandard,name=1
ObjectNameJMImplementation:type=MBeanServerDelegate
1
state:initial stae
修改后 state:new state2
state 使用proxy:new state2
添加Notification监听器
proxy 调用reset方法
来自MBean server通知:状态改变次数重置 ,state重置
来自MBean server通知:状态改变次数重置 ,state重置
 可以最后两行客户端已经收到通话,说明客户端和服务进行了交互,能够通过RMI连接远程的MBean用于应用程序的管理,具体的业务实现类似,回头再写一个和spring整合的JMX。
 
 
 
 


 
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值