Java----------JMX规范

做者:郭无意
连接:https://www.zhihu.com/question/36688387/answer/68667704
来源:知乎
著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

JMX是一种JAVA的正式规范,它主要目的是让程序有被管理的功能。html

那么怎么理解所谓的“被管理”呢?试想你开发了一个软件(如WEB网站),它是在24小时不简断运行的,那么你可能会想要“监控”这个软件的运行状况,好比收到了多少数据,有多少人登陆等等。或者你又想“配置”这个软件,好比如今访问人数比较多,你想把数据链接池设置得大一些;天天的UV、PV是多少;又或者在业务高峰的期间,你想对接口进行限流,就必须去修改接口并发的配置值。java

  应用场景:中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。apache

对于一些参数的修改,网上有一段描述仍是比较形象的:缓存

一、程序初哥通常是写死在程序中,到要改变的时候就去修改代码,而后从新编译发布。架构

二、程序熟手则配置在文件中(JAVA通常都是properties文件),到要改变的时候只要修改配置文件,但仍是必须重启系统,以便读取配置文件里最新的值。并发

三、程序好手则会写一段代码,把配置值缓存起来,系统在获取的时候,先看看配置文件有没有改动,若有改动则从新从配置里读取,不然从缓存里读取。app

四、程序高手则懂得物为我所用,用JMX把须要配置的属性集中在一个类中,而后写一个MBean,再进行相关配置。另外JMX还提供了一个工具页,以方便咱们对参数值进行修改。dom

 

让开发者和管理者能够获取程序运行的状态以及动态的修改程序的相关配置。工具

SUN依据这个规范在JDK提供了JMX接口,而根据这个接口的实现则有不少种,好比Weblogic的JMX实现、MX4J、JBoss的JMX实现。网站

咱们常用的JDK中SUN公司的实如今java.lang.management包下。

JMX架构图:

MBean 即 managed beans 被管理的Beans

 

从图中咱们能够看到,JMX的结构一共分为三层:

一、基础层:主要是MBean,被管理的资源。

MBean分为以下四种,我接下来主要介绍standard MBean

类型描述standard MBean这种类型的MBean最简单,它能管理的资源(包括属性,方法,时间)必须定义在接口中,而后MBean必须实现这个接口。它的命名也必须遵循必定的规范,例如咱们的MBean为Hello,则接口必须为HelloMBean。dynamic MBean必须实现javax.management.DynamicMBean接口,全部的属性,方法都在运行时定义open MBean此MBean的规范还不完善,正在改进中model MBean与标准和动态MBean相比,你能够不用写MBean类,只需使用javax.management.modelmbean.RequiredModelMBean便可。RequiredModelMBean实现了ModelMBean接口,而ModelMBean扩展了DynamicMBean接口,所以与DynamicMBean类似,Model MBean的管理资源也是在运行时定义的。与DynamicMBean不一样的是,DynamicMBean管理的资源通常定义在DynamicMBean中(运行时才决定管理那些资源),而model MBean管理的资源并不在MBean中,而是在外部(一般是一个类),只有在运行时,才经过set方法将其加入到model MBean中。后面的例子会有详细介绍

二、适配层:MBeanServer,主要是提供对资源的注册和管理。

三、接入层:提供远程访问的入口。

JMX超详细解读 - 冬瓜蔡 - 博客园 这篇博客详细介绍了三种使用JMX的方式,下面我提供一下本身实现的例程

 

import java.io.IOException; import java.lang.management.ManagementFactory; import java.rmi.registry.LocateRegistry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.management.MBeanServer; import javax.management.MBeanServerFactory; import javax.management.ObjectName; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import com.sun.jdmk.comm.HtmlAdaptorServer; public class ApplicationServer { private static HtmlAdaptorServer adaptorServer = null; private static javax.management.remote.JMXConnectorServer cs = null; private static Logger logger = null; private static ExecutorService cachedExecutors = null; private static void initExecutor() { cachedExecutors = Executors.newFixedThreadPool(2); } private static void exitExecutor() { cachedExecutors.shutdown(); } public static void execute(final Runnable runnable) { cachedExecutors.execute(runnable); } private static void initLogger() { System.out.println("configuring log4j with log4j.xml"); DOMConfigurator.configure("log4j.xml"); logger = Logger.getLogger("root"); } private static void initHtmlJMX() throws Exception { MBeanServer server = MBeanServerFactory.createMBeanServer(); ObjectName helloName = new ObjectName("jmx:name=HelloWorld"); server.registerMBean(new Hello(), helloName); ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8081"); adaptorServer = new HtmlAdaptorServer(); server.registerMBean(adaptorServer, adapterName); adaptorServer.start(); logger.info("start jmx html server"); } private static int initProtogenesisJMX() throws Exception { String port1Str = System.getProperty("com.jmxport1"); String port2Str = System.getProperty("com.jmxport2"); if (port1Str == null || port2Str == null) { logger.error("jmx端口未经过系统属性设置"); return -1; } final int port1 = Integer.valueOf(port1Str); final int port2 = Integer.valueOf(port2Str); System.setProperty("java.rmi.server.randomIDs", "true"); try { LocateRegistry.createRegistry(port2); } catch (java.rmi.server.ExportException ex) { logger.error("err", ex); return -1; } MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); java.util.HashMap<String, Object> env = new java.util.HashMap<String, Object>(); env.put("jmx.remote.x.password.file", "jmxremote.password"); env.put("jmx.remote.x.access.file", "jmxremote.access"); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://127.0.0.1:" + port1 + "/jndi/rmi://127.0.0.1:" + port2 + "/jmxrmi"); cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); try { cs.start(); } catch (java.net.BindException ex) { logger.error("端口已被占用", ex); return -2; } return 0; } public static void exitHtmlJMX() { adaptorServer.stop(); } public static void exitProtogenesisJMX() throws IOException { cs.stop(); } public static void init() throws Exception { initLogger(); // initHtmlJMX(); initProtogenesisJMX(); initExecutor(); } public static void exit() throws IOException { //exitHtmlJMX(); exitProtogenesisJMX(); exitExecutor(); } public static void main(String[] args) throws Exception { System.setProperty("com.jmxport1", String.valueOf(7000)); System.setProperty("com.jmxport2", String.valueOf(7001)); init(); MBeanServer server = java.lang.management.ManagementFactory.getPlatformMBeanServer(); ObjectName helloName = new ObjectName("jmxBean:name=stopper"); server.registerMBean(new Stopper(), helloName); } public interface StopperMBean { void stop() throws IOException; } public static class Stopper implements StopperMBean { public void stop() throws IOException { ApplicationServer.exit(); } } }

 

import java.text.SimpleDateFormat; import java.util.HashMap; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; public class JMXClient { /** * * @param args * host port username password bean name method ...params * @throws Exception */ public static void main(String[] args) throws Exception { if ((args.length < 6) || (args.length % 2 != 0)) { logErr("params error"); return; } final String host = args[0]; final int rmiPort = Integer.valueOf(args[1]).intValue(); final String username = args[2]; final String password = args[3]; final ObjectName objectName = new ObjectName(args[4]); final String methodName = args[5]; final HashMap<String, String[]> jmxParamsHashMap = new HashMap<String, String[]>(); final String[] usernameAndPassword = { username, password }; jmxParamsHashMap.put("jmx.remote.credentials", usernameAndPassword); final String serviceUrl = new StringBuilder().append("service:jmx:rmi:///jndi/rmi://").append(host).append(":") .append(rmiPort).append("/jmxrmi").toString(); final JMXServiceURL jmxServiceURL = new JMXServiceURL(serviceUrl); final JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL, jmxParamsHashMap); if (jmxConnector == null) { logErr(new StringBuilder().append("connect to jmx failed, url=").append(jmxServiceURL).toString()); return; } log(new StringBuilder().append("JMXConnector=").append(jmxConnector.toString()).toString()); Object[] paramsValue = null; String[] paramsClassName = null; final MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection(); final Object localObject = mBeanServerConnection.invoke(objectName, methodName, paramsValue, paramsClassName); log(new StringBuilder().append("invoke method success, name=").append(objectName).append(", operation=") .append(methodName).append(", retvalue=").append(localObject == null ? "void" : localObject.toString()) .toString()); } static void log(String paramString) { final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss : "); final StringBuilder sBuilder = new StringBuilder(); sBuilder.append(simpleDateFormat.format(Long.valueOf(System.currentTimeMillis()))); sBuilder.append(paramString); System.out.println(sBuilder.toString()); } static void logErr(String paramString) { final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss : "); final StringBuilder sBuilder = new StringBuilder(); sBuilder.append(simpleDateFormat.format(Long.valueOf(System.currentTimeMillis()))); sBuilder.append(paramString); System.err.println(sBuilder.toString()); } }
相关文章
相关标签/搜索