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}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章