Java-技术专题-JMX超详细解读

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"一、JMX的定义"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"  "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。"},{"type":"text","marks":[{"type":"strong"}],"text":"JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服务实现管理。"},{"type":"text","text":"这是官方文档上的定义,我看过很多次也无法很好的理解。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"JMX让程序有被管理的功能,例如你开发一个WEB网站,它是在24小时不间断运行,那么你肯定会对网站进行监控,如每天的UV、PV是多少"},{"type":"text","text":";又或者在业务高峰的期间,你想对接口进行限流,就必须去修改接口并发的配置值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"  "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"应用场景:中间件软件WebLogic管理页面就是基于JMX开发的,JBoss则整个系统都基于JMX构架"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于一些参数的修改,网上有一段描述还是比较形象的:"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"1、程序初哥一般是写死在程序中,到要改变的时候就去修改代码,然后重新编译发布。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 2、程序熟手则配置在文件中(JAVA一般都是properties文件),到要改变的时候只要修改配置文件,但还是必须重启系统,以便读取配置文件里最新的值。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 3、程序好手则会写一段代码,把配置值缓存起来,系统在获取的时候,先看看配置文件有没有改动,如有改动则重新从配置里读取,否则从缓存里读取。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" 4、程序高手则懂得物为我所用,用JMX把需要配置的属性集中在一个类中,然后写一个MBean,再进行相关配置。另外JMX还提供了一个工具页,以方便我们对参数值进行修改。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"二、JMX架构图"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5a/5a232527b7d4dd584c30b22a329f844a.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从图中我们可以看到,JMX的结构一共分为三层:"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1.基础层:主要是MBean,被管理的资源。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MBean分为如下四种,我接下来主要介绍standard MBean"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" standard MBean这种类型的MBean最简单,它能管理的资源(包括属性,方法,时间)必须定义在接口中,然后MBean必须实现这个接口。它的命名也必须遵循一定的规范,例如我们的MBean为Hello,则接口必须为HelloMBean。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#9254DE","name":"purple"}},{"type":"strong"}],"text":"dynamic MBean必须实现javax.management.DynamicMBean接口,所有的属性,方法都在运行时定义open MBean此MBean的规范还不完善,正在改进中model MBean与标准和动态MBean相比,你可以不用写MBean类,只需使用javax.management.modelmbean.RequiredModelMBean即可。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":" "},{"type":"text","marks":[{"type":"color","attrs":{"color":"#40A9FF","name":"blue"}},{"type":"strong"}],"text":"RequiredModelMBean实现了ModelMBean接口,而ModelMBean扩展了DynamicMBean接口,因此与DynamicMBean相似,Model MBean的管理资源也是在运行时定义的。与DynamicMBean不同的是,DynamicMBean管理的资源一般定义在DynamicMBean中(运行时才决定管理那些资源),而model MBean管理的资源并不在MBean中,而是在外部(通常是一个类),只有在运行时,才通过set方法将其加入到model MBean中。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2、适配层:MBeanServer,提供对资源的注册和管理。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3、接入层:提供远程访问的入口。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下来我这里会用程序来介绍三种访问JMX的方式:"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"三、JDK的小工具Jconsole访问"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 1、 首先定义一个MBean接口,接口的命名规范为以具体的实现类为前缀(这个规范很重要)"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" 1 package jmx;\n 3 public interface HelloMBean{\n 5 public String getName(); \n 7 public void setName(String name); \n 9 public String getAge();\n11 public void setAge(String age); \n13 public void helloWorld(); \n15 public void helloWorld(String str); \n17 public void getTelephone();\n18 }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2、定义一个实现类,实现上面的接口:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" 1 package jmx;\n 3 /*\n 4 * 该类名称必须与实现的接口的前缀保持一致(即MBean前面的名称\n 5 */\n 6 public class Hello implements HelloMBean\n 7 {\n 8 private String name;\n 9 \n10 private String age;\n11 \n12 public void getTelephone()\n13 {\n14 System.out.println(\"get Telephone\");\n15 }\n16 \n17 public void helloWorld()\n18 {\n19 System.out.println(\"hello world\");\n20 }\n21 \n22 public void helloWorld(String str)\n23 {\n24 System.out.println(\"helloWorld:\" + str);\n25 }\n26 \n27 public String getName()\n28 {\n29 System.out.println(\"get name 123\");\n30 return name;\n31 }\n32 \n33 public void setName(String name){\n35 System.out.println(\"set name 123\");\n36 this.name = name;\n37 }\n38 \n39 public String getAge(){\n41 System.out.println(\"get age 123\");\n42 return age;\n43 }\n44 \n45 public void setAge(String age)\n46 {\n47 System.out.println(\"set age 123\");\n48 this.age = age;\n49 } \n53 }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3、定义agent层:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" 1 package jmx;\n 3 import java.lang.management.ManagementFactory;\n 5 import javax.management.JMException;\n 6 import javax.management.MBeanServer;\n 7 import javax.management.ObjectName;\n 9 public class HelloAgent{\n11 public static void main(String[] args) throws JMException, Exception{\n13 MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n14 ObjectName helloName = new ObjectName(\"jmxBean:name=hello\");\n15 //create mbean and register mbean\n16 server.registerMBean(new Hello(), helloName);\n17 Thread.sleep(60*60*1000);\n18 }\n19 }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"1、其中第13行是通过工厂类获取MBeanServer,用来做MBean的容器 。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"2、第14行中的ObjectName中的取名是有一定规范的,格式为:“域名:name=MBean名称”,其中域名和MBean的名称可以任意取。这样定义后,就可以唯一标识我们定义这个MBean实现类。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"3、第16行是将Hello这个类注入到MBeanServer中,注入需要创建一个ObjectName类 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"这样,一个简单的JMX的DEMO已经写完了,现在我们通过JDK提供的Jconsole来进行操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 1、首先在自己的本地路径下:C:\\Program Files (x86)\\Java\\jdk1.6.0_43\\bin找到jconsole.exe这个小工具,双击打开:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/eb/eb72535e7046bf39fdf003516fcf0c4a.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2、双击打开我们的本地进程:HelloAgent:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/18/180c4630e81f48981aca854c2166cfe9.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3.在这个界面上,我们可以给程序中HelloMBean的属性赋值,也可以调用其中的方法:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/87/870a6b549ab8c0df62b8be3417575687.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4、控制台打印如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/50/508381731e428d674f0640c581cce2e9.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"四、通过JMX提供的工具页访问"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里,我们复用上面的接口和实现类,只需要改动适配层,这里需要到导入外部jar包jdmk"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\nimport java.lang.management.ManagementFactory;\nimport javax.management.JMException;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\nimport com.sun.jdmk.comm.HtmlAdaptorServer;\n\npublic class HelloAgent\n{\n public static void main(String[] args) throws JMException, Exception\n {\n MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n ObjectName helloName = new ObjectName(\"jmxBean:name=hello\");\n //create mbean and register mbean\n server.registerMBean(new Hello(), helloName);\n ObjectName adapterName = new ObjectName(\"HelloAgent:name=htmladapter,port=8082\"); \n HtmlAdaptorServer adapter = new HtmlAdaptorServer(); \n server.registerMBean(adapter, adapterName); \n adapter.start();\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们访问地址:"},{"type":"link","attrs":{"href":"http://localhost:8082/","title":null},"content":[{"type":"text","text":"http://localhost:8082"}],"marks":[{"type":"underline"}]},{"type":"text","text":",点击name=hello:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/76/7615fbe6bc61db15994ba2381d57649a.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/91/91373557db5b8b40afd2cc8b4ddbf0f8.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 1、在这里创建一个"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"AdaptorServer"},{"type":"text","text":",这个类将决定"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"MBean"},{"type":"text","text":"的管理界面,这里用最普通的"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"Html"},{"type":"text","text":"型界面。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"AdaptorServer"},{"type":"text","text":"其实也是一个"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"MBean"},{"type":"text","text":"。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 2、我们可以看到这个工具页,其实与我们上一个案例中的"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"Jconsole"},{"type":"text","text":"中的管理界面类似,都可以操作资源中的属性和方法。"}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"五、通过客户端程序进行远程访问"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 1、这里需要对agent进行修改,增加ip和port绑定部分的逻辑"},{"type":"link","attrs":{"href":"javascript:void(0);","title":"复制代码"},"marks":[{"type":"underline"}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1f/1f27030192d8c44f558bb4a7fe29951b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"写到这里,如果没有client进行远程连接,可以使用"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"Jconsole"},{"type":"text","text":"进行远程访问:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8e/8e7385a76f3760b70b4fcfeecacc8dbb.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2、客户端Client程序,用于与agent进行远程连接:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":" 1 package jmx;\n 3 import java.io.IOException;\n 5 import javax.management.Attribute;\n 6 import javax.management.MBeanServerConnection;\n 7 import javax.management.MBeanServerInvocationHandler;\n 8 import javax.management.ObjectName;\n 9 import javax.management.remote.JMXConnector;\n10 import javax.management.remote.JMXConnectorFactory;\n11 import javax.management.remote.JMXServiceURL;\n12 \n14 public class Client{\n16 public static void main(String[] args) throws IOException, Exception, NullPointerException{\n18 JMXServiceURL url = new JMXServiceURL\n19 (\"service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi\");\n20 JMXConnector jmxc = JMXConnectorFactory.connect(url,null);\n22 MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();\n23 //ObjectName的名称与前面注册时候的保持一致\n24 ObjectName mbeanName = new ObjectName(\"jmxBean:name=hello\");\n26 System.out.println(\"Domains ......\");\n27 String[] domains = mbsc.getDomains();\n29 for(int i = 0;i < domains.length ; i++){\n31 System.out.println(\"domain[\" + i + \"]=\" + domains[i] );\n32 }\n34 System.out.println(\"MBean count = \" + mbsc.getMBeanCount());\n35 //设置指定Mbean的特定属性值\n36 //这里的setAttribute、getAttribute操作只能针对bean的属性\n37 //例如对getName或者setName进行操作,只能使用Name,需要去除方法的前缀\n38 mbsc.setAttribute(mbeanName, new Attribute(\"Name\",\"杭州\"));\n39 mbsc.setAttribute(mbeanName, new Attribute(\"Age\",\"1990\"));\n40 String age = (String)mbsc.getAttribute(mbeanName, \"Age\");\n41 String name = (String)mbsc.getAttribute(mbeanName, \"Name\");\n42 System.out.println(\"age=\" + age + \";name=\" + name);\n44 HelloMBean proxy = MBeanServerInvocationHandler.\n45 newProxyInstance(mbsc, mbeanName, HelloMBean.class, false);\n46 proxy.helloWorld();\n47 proxy.helloWorld(\"migu\");\n48 proxy.getTelephone();\n49 //invoke调用bean的方法,只针对非设置属性的方法\n50 //例如invoke不能对getName方法进行调用\n51 mbsc.invoke(mbeanName, \"getTelephone\", null, null);\n52 mbsc.invoke(mbeanName, \"helloWorld\", new String[]{\"I'll connect to JMX Server via client2\"}, new String[]{\"java.lang.String\"});\n54 mbsc.invoke(mbeanName, \"helloWorld\", null, null);\n55 }\n56 }"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" a、在35到41行,是对属性进行赋值和取值,这里我们不能直接调用方法,而是通过setAttribute、getAttrubute方法来进行操作,则属性的首字母要大写。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" b、对资源里面的方法进行操作有两种方式:一是通过代理直接调用方法;二是通过JAVA的反射注入的方式进行方法的调用。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面我们来看看执行结果,先执行agent,再执行客户端:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":" c、client的控制台打印结果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c8/c8863e85f2d96c76178f87ba92ee6fcd.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"d、agent控制台打印结果:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/51/5122b10b402fdd3893822945ec79862d.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"六、Notification"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"  "},{"type":"text","marks":[{"type":"strong"}],"text":"MBean"},{"type":"text","text":"之间的通信是必不可少的,"},{"type":"text","marks":[{"type":"strong"}],"text":"Notification"},{"type":"text","text":"就起到了在"},{"type":"text","marks":[{"type":"strong"}],"text":"MBean"},{"type":"text","text":"之间沟通桥梁的作用。JMX 的通知由四部分组成:"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"1、Notification这个相当于一个信息包,封装了需要传递的信息"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"2、Notification broadcaster这个相当于一个广播器,把消息广播出。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"3、Notification listener 这是一个监听器,用于监听广播出来的通知信息。"}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}},{"type":"strong"}],"text":"4、Notification filiter 这个一个过滤器,过滤掉不需要的通知。这个一般很少使用。"}]}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里我们使用日常打招呼的场景:jack与我偶遇,jack说:hi;我礼貌的回答:hello,jack。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这里我们先分别创建两个资源:"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\n\n/*\n * 该类名称必须与实现的接口的前缀保持一致(即MBean前面的名称\n */\npublic class Hello implements HelloMBean\n{\n private String name;\n\n public String getName()\n {\n return name;\n }\n\n public void setName(String name)\n {\n this.name = name;\n }\n\n public void printHello()\n {\n System.out.println(\"Hello World, \" + name);\n }\n\n public void printHello(String whoName)\n {\n System.out.println(\"Hello , \" + whoName);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\n/*\n * 接口名必须以MBean结尾\n */\npublic interface HelloMBean\n{\n public String getName(); \n public void setName(String name); \n public void printHello(); \n public void printHello(String whoName);\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\nimport javax.management.Notification;\nimport javax.management.NotificationBroadcasterSupport;\npublic class Jack extends NotificationBroadcasterSupport implements JackMBean\n{\n private int seq = 0;\n public void hi()\n {\n //创建一个信息包\n Notification notify = \n //通知名称;谁发起的通知;序列号;发起通知时间;发送的消息\n new Notification(\"jack.hi\",this,++seq,System.currentTimeMillis(),\"jack\");\n sendNotification(notify);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\npublic interface JackMBean{\n public void hi();\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 这里的类Jack不仅实现了MBean接口,还继承了NotificationBroadcasterSupport。jack在这里创建并发送了一个消息包。"}]},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\nimport javax.management.Notification;\nimport javax.management.NotificationListener;\npublic class HelloListener implements NotificationListener{\n public void handleNotification(Notification notification, Object handback){\n if(handback instanceof Hello){\n Hello hello = (Hello)handback;\n hello.printHello(notification.getMessage());\n }\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":null},"content":[{"type":"text","text":"package jmx;\n\nimport java.lang.management.ManagementFactory;\n\nimport javax.management.JMException;\nimport javax.management.MBeanServer;\nimport javax.management.ObjectName;\n\npublic class HelloAgent\n{\n public static void main(String[] args) throws JMException, Exception{\n MBeanServer server = ManagementFactory.getPlatformMBeanServer();\n ObjectName helloName = new ObjectName(\"yunge:name=Hello\"); \n Hello hello=new Hello(); \n server.registerMBean(hello, helloName); \n Jack jack = new Jack();\n server.registerMBean(jack, new ObjectName(\"jack:name=Jack\"));\n jack.addNotificationListener(new HelloListener(), null, hello);\n Thread.sleep(500000);\n }\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我们用Jconsole来进行访问:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f1/f1a932aa39941dc9d94cdcbfdc43029d.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 这里我们可以看到有两个MBean,一个是yunge,一个是jack。我们执行jack的hi方法后,去看下控制台上的打印信息;"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6a/6ac3783144b2a474d38477b79e471c4a.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"七、linux下利用JMX监控Tomcat"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"  利用JMX监控Tomcat,就是相当于部署在tomcat上的应用作为服务端,也就是被管理资源的对象。然后通过程序或者jconsole远程连接到该应用上来。远程连接需要服务器端提供ip和port。如果需要加密访问的话,还需要配置用户名、密码等参数。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 主要是在tomcat下的文件catalina.sh中进行一些环境变量的配置配置:"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ec/ec143e0a00d3335af15ec44e0a7f2c59.png","alt":"","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"-Dcom.sun.management.jmxremote=true                 相关 JMX 代理侦听开关"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"-Djava.rmi.server.hostname                                     服务器端的IP"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"-Dcom.sun.management.jmxremote.port=29094             相关 JMX 代理侦听请求的端口"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"-Dcom.sun.management.jmxremote.ssl=false              指定是否使用 SSL 通讯"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"-Dcom.sun.management.jmxremote.authenticate=false     指定是否需要密码验证"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这样就可以通过客户端或者jconsole对tomcat进行监控。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章