JMX(Java Management Extensions:即java管理扩展)是一个为应用程序,设备,系统等植入管理功能的框架,
JMX可以跨越一系列异构操作系统平台,系统体系架构和网络传输协议,灵活的开发无缝集成的系统,网络和服务管理应用.
应用场景:在一个系统中通常会有一些配置信息,例如服务器的IP地址和端口号,并且这些信息可能在系统运行的过程中经常需要改动,
面对这样的问题,怎么办呢?如下提供了四种解决方法.
1.一种方法是:将这些信息写死在代码里,当需要修改某些配置时,修改代码,然后将修改完的代码重新编译,将服务重新部署,并重新启动.
2.二种方法是:用配置文件来保存这些信息,省去了编译代码步骤,但是仍然需要重新启动服务.
3.三种方法是:用配置文件来保存这些信息,并让系统在运行时定期检查配置文件是否发生变化,如果发生变化重新读取数据放入缓存中,
这种方法是经常用的,但是额外增加了系统的繁琐性.
4.四种方法是:JMX为我们提供了更好的解决方案,我们可以把配置信息封装在一个称为MBean的对象中,
JMX提供了现成的用户接口(例如jconsole)使我们在系统运行过程中修改这些信息,并且不需要重启服务.
JDK工具套装中的jconsole是一个JMX兼容的图形界面工具,它能够连接到本地或远程的JVM,检测JVM的运行情况,
例如内存使用情况,线程的数量,已装入类的数目等,jconsole将这些JVM的数据以图形化的方式直观展现给用户.
JMX机构分为三层:自下向上依次是:设备层,代理层和分布式服务层.
设备层:定义成包括所有被管理和监测的资源,我们把这些资源统称为托管资源,托管资源被包装成一个MBean,
以便资源能够被JMX兼容的应用程序(例如jconsole)所管理.MBean共有四种类型:标准Bean,动态Bean,开放Bean和模型Bean.
代理层:代理层的实现是MBeanServer对象,所有的MBean对象都需要注册到MBeanServer上,以便被查询和控制.
分布式服务:分布式服务定义了JMX应用程序所需的接口,JMX应用程序通过该接口与MBean进行交互.
JMX约定:注册MBeanServer的MBean名称后缀必须是MBean,否则JMX无法识别.例如如果想将类名Log(包含三个属性id,name,log)的类注册到JMX,
需要为Log类定义接口LogMBean.在LogMean中如果包含属性的get方法,那么会在jconsole窗口中对应的属性列表中看到,
如果定义了其他方法(非get方法),会在jconsole窗口中对应的操作列表中看到.
下面通过一个简单的实例来学习一下JMX的使用,实例目的:控制各个模块的日志是否记录.
1.查看MBean类,直接看代码Log和LogMBean.
<span style="font-size:12px;">package com.ilucky.jmx.model; /** * @author IluckySi * @date 20140730 */ public class Log implements LogMBean { private int id; private String name; private boolean log; public Log(int id, String name, boolean log) { this.id = id; this.name = name; this.log = log; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { System.out.println("修改日志审计模块名称为: " + name); this.name = name; } public boolean isLog() { return log; } public void setLog(boolean log) { System.out.println("修改日志审计模块结果为: " + log); this.log = log; } public void changeName(String name) { setName(name); } public void changeLog(boolean log) { setLog(log); } public void test1() { System.out.println("测试1: Hello Word!"); } public void test2(int a, int b) { System.out.println("测试2: a + b = " + (a + b)); } } </span>
<span style="font-size:12px;">package com.ilucky.jmx.model; /** * @author IluckySi * @date 20140730 */ public interface LogMBean { public int getId(); public String getName(); public boolean isLog(); public void changeName(String name); public void changeLog(boolean log); public void test1(); public void test2(int a, int b); } </span>
2.查看MBeanServer类,直接看代码MyMBeanServer.
<span style="font-size:12px;">package com.ilucky.jmx.server; import java.lang.management.ManagementFactory; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; /** * @author IluckySi * @date 20140730 */ public class MyMBeanServer { public static MyMBeanServer instance; private static MBeanServer mBeanServer; public static MyMBeanServer getInstance() { if(instance == null) { instance = new MyMBeanServer(); } return instance; } private MyMBeanServer() { mBeanServer = ManagementFactory.getPlatformMBeanServer(); } public void registerMBean(Object object, ObjectName objectName) { try { mBeanServer.registerMBean(object, objectName); } catch (InstanceAlreadyExistsException e) { System.out.println("向Jmx Server注册MBean发生问题: " + e.toString()); } catch (MBeanRegistrationException e) { System.out.println("向Jmx Server注册MBean发生问题: " + e.toString()); } catch (NotCompliantMBeanException e) { System.out.println("向Jmx Server注册MBean发生问题: " + e.toString()); } } } </span>
3.最后看测试类MainTest.
<span style="font-size:12px;">package com.ilucky.jmx; import javax.management.ObjectName; import com.ilucky.jmx.model.Log; import com.ilucky.jmx.model.LogMBean; import com.ilucky.jmx.server.MyMBeanServer; /** * @author IluckySi * @date 20140730 */ public class MainTest { public static void main(String[] args) { try { //获取MBeanServer并注册MBean. MyMBeanServer myMBeanServer = MyMBeanServer.getInstance(); ObjectName objectName = new ObjectName("com.ilucky.jmx:model=LogMBean"); LogMBean logMBean = new Log(21, "司冬雪", false); myMBeanServer.registerMBean(logMBean, objectName); //让服务一直处于等待中以便测试. Thread.sleep(Integer.MAX_VALUE); } catch (Exception e) { System.out.println("测试发生问题: " + e.toString()); } } } /** 执行结果: 修改日志审计模块名称为: sdx 修改日志审计模块名称为: sdx2 修改日志审计模块结果为: true 修改日志审计模块结果为: false 测试1: Hello Word! 测试1: Hello Word! 测试2: a + b = 33 测试2: a + b = 335 */ </span>
4.最后在cmd窗口运行jconsole指令,打开图形界面(简单截了几张图).