JMX基本构架:
JMX分为三层,分别负责处理不同的事务。它们分别是:
Instrumentation 层:
Instrumentation层主要包括了一系列的接口定义和描述如何开发MBean的规范。
通常JMX所管理的资源有一个或多个MBean组成,因此这个资源可以是任何由Java语言开发的组件,
或是一个JavaWrapper包装的其他语言开发的资源。
Agent 层:
Agent 用来管理相应的资源,并且为远端用户提供访问的接口。
Agent层构建在Intrumentation层之上,并且使用并管理 Instrumentation层内部描述的组件。
通常Agent由一个MBeanServer和多个系统服务组成。
另外Agent还提供一个或多个 Adapter或Connector以供外界的访问。
JMX Agent并不关心它所管理的资源是什么。
Distributed 层
Distributed层关心Agent如何被远端用户访问的细节。
它定义了一系列用来访问Agent的接口和组件,包括Adapter和Connector的描述。
JMX术语:
MBean:
是Managed Bean的简称。在JMX中MBean代表一个被管理的资源实例。
通过MBean中暴露的方法和属性,外界可以获取被管理的资源的状态和操纵MBean的行为。
MBean分为四种类型: 标准、动态、开放、模型。
MBean生存在一个MBeanServer中。MBeanServer管理这些MBean,并且代理外界对它们的访问。
MBeanServer提供了一种注册机制,是的外界可以通过名字来得到相应的MBean实例。
Agent只是一个Java进程,它包括这个MBeanServer和一系列附加的MbeanService。
当然这些Service也是通过MBean的形式来发布。
JMX Agent通过各种各样的Adapter和Connector来与外界(JVM之外)进行通信。
同样外界(JVM之外)也必须通过某个Adapter和Connector来向JMX Agent发送管理或控制请求。
Adapter 和Connector的区别在于:Adapter是使用某种Internet协议来与JMX Agent获得联系。
Agent端会有一个对象 (Adapter)来处理有关协议的细节。
JMX Agent可以带有任意多个Adapter,因此可以使用多种不同的方式访问Agent。
下面是实例
HelloBean.java // 接口
package com.sscc.jmx;
public interface HelloMBean {
public String getName();
public void setName(String name);
public void printHello();
public void printHello(String whoName);
}
Hello.java // 实现类(标准MBean)
package com.sscc.jmx;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
/* Standard MBean */
public class Hello extends NotificationBroadcasterSupport implements HelloMBean {
private String name;
private boolean writable;
@Override
public String getName() {
// TODO Auto-generated method stub
return name;
}
@Override
public void setName(String name) {
// TODO Auto-generated method stub
this.name = name;
}
public boolean isWritable() {
return writable;
}
public void setWritable(boolean writable) {
this.writable = writable;
}
@Override
public void printHello() {
final Notification notification = new Notification("com.sscc.jmx.hello", this, -1,
System.currentTimeMillis(), "printHello is called");
sendNotification(notification);
// TODO Auto-generated method stub
System.out.println("Hello World");
}
@Override
public void printHello(String whoName) {
final Notification notification = new Notification("com.sscc.jmx.hello", this, -1,
System.currentTimeMillis(), "printHello with name is called");
sendNotification(notification);
// TODO Auto-generated method stub
System.out.println("Hello!" + whoName);
}
}
HelloListener.java // 监听类
package com.sscc.jmx;
import javax.management.Notification;
import javax.management.NotificationListener;
public class HelloListener implements NotificationListener {
public void handleNotification(Notification notification, Object o) {
System.out.println(this.getClass().getName() +
" Notification Listener --" + notification.getMessage());
}
}
ModelMBeanUtils.java //实现类(模型MBean)
package com.sscc.jmx;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanConstructorInfo;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import javax.management.modelmbean.RequiredModelMBean;
public class ModelMBeanUtils {
public RequiredModelMBean createModlerMBean(@SuppressWarnings("rawtypes") Class cls) {
RequiredModelMBean model = null;
try {
model = new RequiredModelMBean();
model.setManagedResource(new Hello(), "ObjectReference");
ModelMBeanInfo info = createModelInfo(cls);
model.setModelMBeanInfo(info);
} catch (Exception e) {
e.printStackTrace();
}
return model;
}
@SuppressWarnings("unchecked")
public Method getGetMethodName(@SuppressWarnings("rawtypes") Class cls, Field prop) {
if (prop == null) {
return null;
}
String methodName;
if (prop.getType().equals(Boolean.class) || prop.getType().equals(boolean.class)) {
methodName = "is" + prop.getName().substring(0,1).toUpperCase() + prop.getName().substring(1);
} else {
methodName = "get" + prop.getName().substring(0,1).toUpperCase() + prop.getName().substring(1);
}
try {
return cls.getMethod(methodName, (Class[])null);
} catch (Exception e) {
}
return null;
}
@SuppressWarnings("unchecked")
public Method getSetMethodName(@SuppressWarnings("rawtypes") Class cls, Field prop) {
if (prop == null) {
return null;
}
String methodName = "set" + prop.getName().substring(0,1).toUpperCase() + prop.getName().substring(1);
try {
return cls.getMethod(methodName, prop.getType());
} catch (Exception e) {
}
return null;
}
private ModelMBeanInfo createModelInfo(@SuppressWarnings("rawtypes") Class cls) throws Exception {
Field[] fields = cls.getDeclaredFields();
Method getMethod = null;
Method setMethod = null;
ModelMBeanAttributeInfo[] nameAttrInfo = new ModelMBeanAttributeInfo[fields.length];
for(int i = 0;i<= fields.length - 1; i++) {
getMethod = getGetMethodName(cls, fields[i]);
setMethod = getSetMethodName(cls, fields[i]);
nameAttrInfo[i] = new ModelMBeanAttributeInfo(
fields[i].getName(),
"field description",
getMethod,setMethod,
null
);
}
@SuppressWarnings("rawtypes")
Constructor[] Constructors = cls.getDeclaredConstructors();
ModelMBeanConstructorInfo[] print1Info = new ModelMBeanConstructorInfo[Constructors.length];
for(int i = 0;i<= Constructors.length - 1; i++) {
print1Info[i] = new ModelMBeanConstructorInfo(
"Constructors description",
Constructors[i]
);
}
Method[] methods = cls.getMethods();
ModelMBeanOperationInfo[] print2Info = new ModelMBeanOperationInfo[methods.length];
for(int i = 0;i<= methods.length - 1; i++) {
print2Info[i] = new ModelMBeanOperationInfo(
"Constructors description",
methods[i]
);
}
// create ModelMBeanInfo
ModelMBeanInfo mbeanInfo = new ModelMBeanInfoSupport(//
RequiredModelMBean.class.getName(), // MBean Name
"class description", // description
nameAttrInfo, // Properties
print1Info, // Constructors
print2Info, // Methods
null, // ModelMBeanNotificationInfo
null // MBean description
);
return mbeanInfo;
}
}
HtmlServerAgent.java // Adapter类
package com.sscc.jmx;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import com.sun.jdmk.comm.HtmlAdaptorServer;
public class HtmlServerAgent implements Agent {
private int connectorPort = 8082;
public int getConnectorPort() {
return connectorPort;
}
public void setConnectorPort(int connectorPort) {
this.connectorPort = connectorPort;
}
private MBeanServer mBeanServer;
private HtmlAdaptorServer htmlAdaptorServer;
// constructor
public HtmlServerAgent(MBeanServer mBeanServer) {
this.mBeanServer = mBeanServer;
}
// Start HtmlAdaptorServer
public void StartServer() throws Exception {
this.htmlAdaptorServer = new HtmlAdaptorServer();
ObjectName hasName = new ObjectName("DefaultDomain:name=HTMLAdaptor");
htmlAdaptorServer.setPort(connectorPort);
mBeanServer.registerMBean(htmlAdaptorServer, hasName );
htmlAdaptorServer.start();
System.out.println("HTMLAdaptorServer start");
}
}
JMXConnectorServerAgent.java // Connector类
package com.sscc.jmx;
import javax.management.Attribute;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
public class JMXConnectorServerAgent implements Agent {
private int connectorPort = 1099;
public int getConnectorPort() {
return connectorPort;
}
public void setConnectorPort(int connectorPort) {
this.connectorPort = connectorPort;
}
private MBeanServer mBeanServer;
// constructor
public JMXConnectorServerAgent(MBeanServer mBeanServer) {
this.mBeanServer = mBeanServer;
}
// Start HtmlAdaptorServer
public void StartServer() throws Exception {
// NamingService MBean
ObjectName namingName = ObjectName.getInstance("naming:type=rmiregistry");
mBeanServer.registerMBean(Class.forName("mx4j.tools.naming.NamingService").newInstance(), namingName);
Attribute attr = new Attribute("Port", Integer.valueOf(connectorPort));
mBeanServer.setAttribute(namingName, attr);
// Start NamingService
try {
mBeanServer.invoke(namingName, "start", null, null);
} catch (Exception e) {
}
// JMXServiceURL
JMXServiceURL jmxUrl;
// JMXConnectorServer
int namingPort = ((Integer)mBeanServer.getAttribute(namingName, "Port")).intValue();
// 2. jndiPath
String jndiPath = "/jmxconnector";
// 3. JMXServiceURL
jmxUrl = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:"
+ namingPort + jndiPath);
// 4.Create and start the RMIConnectorServer
JMXConnectorServer connectorServer = JMXConnectorServerFactory
.newJMXConnectorServer(jmxUrl, null, mBeanServer);
connectorServer.start();
System.out.println("JMXConnectorServer start");
}
}
Server.java // server端的主程序
package com.sscc.jmx;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.modelmbean.RequiredModelMBean;
public class Server {
private MBeanServer mBeanServer;
public MBeanServer getmBeanServer() {
return mBeanServer;
}
public void setmBeanServer(MBeanServer mBeanServer) {
this.mBeanServer = mBeanServer;
}
public Server() {
//server = ManagementFactory.getPlatformMBeanServer();
mBeanServer = MBeanServerFactory.createMBeanServer();
}
public void startAgent(Agent agent) throws Exception {
agent.StartServer();
}
public void addBean(Object object, ObjectName objectName) throws Exception {
mBeanServer.registerMBean(object, objectName);
}
public static void main(String[] args) {
try {
Server server = new Server();
HelloMBean hello = new Hello();
HelloListener helloListener = new HelloListener();
((Hello)hello).addNotificationListener(helloListener, null, null);
ObjectName helloName = new ObjectName("thisDomain:name=hello");
server.addBean(hello, helloName);
ModelMBeanUtils modelMBeanUtils = new ModelMBeanUtils();
RequiredModelMBean requiredModelMBean = modelMBeanUtils.createModlerMBean(Hello.class);
ObjectName helloModelName = new ObjectName("thisDomain:name=helloModel");
server.addBean(requiredModelMBean, helloModelName);
// HtmlServerAgent start
Agent agent1 = new HtmlServerAgent(server.getmBeanServer());
server.startAgent(agent1);
// JMXConnectorServerAgent start
Agent agent2 = new JMXConnectorServerAgent(server.getmBeanServer());
server.startAgent(agent2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
HelloClient.java //客户端调用
package com.sscc.jmx;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class HelloClient {
private JMXServiceURL jmxUrl;
private JMXConnector connector;
private MBeanServerConnection mBeanServerconnection;
public HelloClient() throws Exception{
createJMXRmiConnector();
createMBeanServerConnection();
}
private void createJMXRmiConnector() throws Exception{
// 1.The JMXConnectorServer protocol
String serverProtocol = "rmi";
// 2.The RMI server's host
// this is actually ignored by JSR 160
String serverHost = "localhost";
// 3.The host, port and path where the rmiregistry runs.
String namingHost = "localhost";
int namingPort = 1099;
String jndiPath = "/jmxconnector";
// 4. connector server url
jmxUrl = new JMXServiceURL("service:jmx:" +
serverProtocol + "://" + serverHost +
"/jndi/rmi://" + namingHost + ":" +
namingPort + jndiPath);
// Connect a JSR 160 JMXConnector to the server side
connector = JMXConnectorFactory.connect(jmxUrl);
}
private void createMBeanServerConnection() throws Exception{
mBeanServerconnection = connector.getMBeanServerConnection();
}
public void test()throws Exception{
ObjectName oName = new ObjectName("thisDomain", "name", "hello");
// 获取代理对象
Object proxy = MBeanServerInvocationHandler
.newProxyInstance(mBeanServerconnection,oName, HelloMBean.class, true);
HelloMBean helloMBean = (HelloMBean)proxy;
helloMBean.setName("myname");
helloMBean.printHello();
helloMBean.printHello("haha");
// 直接调用
ObjectName modelName = new ObjectName("thisDomain", "name", "helloModel");
mBeanServerconnection.invoke(modelName, "printHello", null, null);
}
public static void main(String[] args) throws Exception {
HelloClient hc = new HelloClient();
hc.test();
}
}
执行Server.java的main方法,启动服务。
然后可以去通过浏览器 http://localhost:8082 调用Mbean的方法。
也可以执行HelloClient.java的main, 通过客户端程序调用MBean。
以上程序需要的jar
jmxremote_optional.jar
jmxremote.jar
jmxri.jar
jmxtools.jar
mx4j-tools.jar
naming-management-0.8.jar
rmissl.jar
org.apache.commons.lang_2.6.0.v201205030909.jar