Java中JMX管理器的作用,專案中有什麼具體使用?
作者:wuxinliulei
連結:https://www.zhihu.com/question/36688387/answer/68667704
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
JMX是一種JAVA的正式規範,它主要目的是讓程式有被管理的功能。
那麼怎麼理解所謂的“被管理”呢?試想你開發了一個軟體(如WEB網站),它是在24小時不簡斷執行的,那麼你可能會想要“監控”這個軟體的執行情況,比如收到了多少資料,有多少人登入等等。或者你又想“配置”這個軟體,比如現在訪問人數比較多,你想把資料連線池設定得大一些;每天的UV、PV是多少;又或者在業務高峰的期間,你想對介面進行限流,就必須去修改介面併發的配置值。
應用場景:中介軟體軟體WebLogic的管理頁面就是基於JMX開發的,而JBoss則整個系統都基於JMX構架。
對於一些引數的修改,網上有一段描述還是比較形象的:
1、程式初哥一般是寫死在程式中,到要改變的時候就去修改程式碼,然後重新編譯釋出。
2、程式熟手則配置在檔案中(JAVA一般都是properties檔案),到要改變的時候只要修改配置檔案,但還是必須重啟系統,以便讀取配置檔案裡最新的值。
3、程式好手則會寫一段程式碼,把配置值快取起來,系統在獲取的時候,先看看配置檔案有沒有改動,如有改動則重新從配置裡讀取,否則從快取裡讀取。
4、程式高手則懂得物為我所用,用JMX把需要配置的屬性集中在一個類中,然後寫一個MBean,再進行相關配置。另外JMX還提供了一個工具頁,以方便我們對引數值進行修改。
讓開發者和管理者可以獲取程式執行的狀態以及動態的修改程式的相關配置。
SUN依據這個規範在JDK提供了JMX介面,而根據這個介面的實現則有很多種,比如Weblogic的JMX實現、MX4J、JBoss的JMX實現。
我們經常使用的JDK中SUN公司的實現在java.lang.management包下。
JMX架構圖:
MBean 即 managed beans 被管理的Beans
從圖中我們可以看到,JMX的結構一共分為三層:
1、基礎層:主要是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中。後面的例子會有詳細介紹
2、適配層:MBeanServer,主要是提供對資源的註冊和管理。
3、接入層:提供遠端訪問的入口。
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());
}
}