JMX是一个管理和监控应用系统和网络设备的技术。这项技术使你可以部署一些叫做MBeans的特殊Java类作为软件代理并和它们在运行期交互。
为什么JXM很重要?
在JDK1.5中,JMX是Java平台标准的一部分。它也是许多J2EE应用服务器的基础(包括JBoss,Websphere和weblogic)。通过理解JMX技术,你将会更容易的使用这些应用服务器并且使用这项技术来开发你自己的扩展功能。
JMX架构
JMX是由三层架构组成。每一层在创建管理资源上都有自己的责任。这些层分别是Instrumentation,Angent,和Remote Management。如图所示架构示意图。
每一层的作用描述如下:
Instrumentation:定义资源(叫做MBeans),让它们在JMX架构中被管理。这些资源可以是任何来自应 用、服务,或者网络设备。
Agent:用来管理,部署,事件通知和监控的基础设施结构。所有和设备化的资源的交互在Agent层发生。最重要的组件是MBeanServer。
RemoteManagement:通过制定协议的adaptors和connectors,定义和agent的外部沟通。adaptor允许客户端应用和MBeanServer交互。一个MBeanServer必须至少部署在一个adaptor上。不同的协议有大量的adaptors。HTTP,RMI和SMTP都是一些和MBeanServer交互的一些基础adaptors。
创建并管理一个标准MBean
最简单的JMX的例子事实上也是很强大的。发布一个可管理beans的步骤如下:
1、建立一个被管理的bean,指定MBean规范遵循的接口。在这个例子中,叫做WorkerMBean。
2、不熟WorkerMBean到MBeanServer。
3、通过管理控制台操作MBean。
首先,关注WorkerMBean的代码,它包含一个接口和一个实现类。对于标准的mbeans,接口名必须以MBean结尾。接口定义一个叫Running的属性,使用setRunning()和isRunning方法。这和Javabean命名规范一致。接口也定义了三个操作,start()。stop,和calcGreeting()。接口定义要暴露给MBeanServer的服务。
package com.wisely.jmx;
public interface WorkerMBean {
public boolean isRunning();
public void setRunning(boolean running);
public void start();
public void stop();
public String calcGreeting( );
}
下一步就是实现这个接口。在实现类中必须遵循三条规则
a、实现类必须和MBean接口在相同的包里
b、实现类必须是接口去掉MBean后归来命名(本例为Worker)
c、实现类必须有个公共的无参构造函数
下面是这个例子的实现。重点是你有有一个带有监控状态方法的MBean,在本例中这个状态是Running。你拥有一个简单的方法叫做calcGreeting(),代表你正在提供的服务:
package com.wisely.jmx;
import java.util.Calendar;
public class Worker implements WorkerMBean {
boolean running = false;
public boolean isRunning() {}
public void setRunning(boolean running) {
this.running = running;
}
public void start() {
running = true;
}
public void stop() {
running = false;
}
public String calcGreeting() {
if (!isRunning())
return “not available”;
Calendar time = Calendar.getInstance();
if (time.get(Calendar.AM_PM) == 0) {
return “good morning”;
} else {
return “good evening”;
}
}
}
下一步是将MBean部署到MBeanServer,作为运行的Agent的一部分。首先通过运行中的JVM向MBeanServer发送请求。然后创建一个ObjectName来引用MBean。所有的MBeans需要有一个被叫做ObjectName的唯一名字。最后注册WokerMBean到MBeanServer:
package com.wisely.jmx;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
public class Agent {
public static void main(String[] args) {
Worker worker = new Worker();
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = new ObjectName("com.wisely.jmx:type=Worker");
mbs.registerMBean(worker, name);
System.out.println("Agent Started..");
Thread.sleep(Long.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
}
因为所有的Mbeans都唯一的和一个MBean server相关,它们的object name有一个特殊的格式。一个ObjectName有2部分组成,一个domain和一个name值对 用等号分开:
com.wisely.jmx:type=Woker
下一步就是运行agent并通过标准管理控制台连接agent。可以使用JDK1.6包含的JConsole。
先运行启动Agent类;
控制台,输入命令JConsole,出现界面:
JConsole是一个用来连接和管理你的可管理资源的管理应用。上图可以看出有2种连接:本地和远程。
在此例中使用本地。选择要连接的Agent-com.wisely.jmx.Agent。
JConsole应用有许多关于代理JVM的health and memory usage 的有用信息。选择MBean标签,这样你可以和你刚不熟的MBean交互,如下图:
MBeans 表现显示所有部署到JVM上的可管理Java对象。选择操作(Operatons)字节点并点击按calcGreeting按钮。
当running状态为false时:
当running状态是true时:
这个例子展示了一个和在运行中JVM Java对象的有状态的交互。这使标准的JavaBean可以部署到MBean server。
JMX 管理
2个JSR规范定义JMX技术:
a、JSR003:Java Management Extensions (JMXTM) Specification API 1.2
b、JSR160:Java Management Extensions (JMX) Remote API 1.0
这节的例子展示JMX API的管理特性。按照下列的步骤:
1、创建一个RemoteAgent,通过RMI注册可以访问。
2、通过一个远程客户端连接agent
3、查询MBeanServer上部署的MBeans
4、部署一个监控MBean并当MBean改变的时候接受通知
RemoteAgent
你可以通过包名可以分辨出RemoteAgent使用javax.management和javax.management.remote包。这些remote包的定义为创建远程连接到服务器,让agent能接受外部处理请求,提供了标准。
package com.wisely.jmx;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
下面的代码创建一个MBeanServer,注册ConnectorServer,然后开始连接来监听请求:
public class RemoteAgent {
public static void main(String[] args) throws Exception {
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
JMXServiceURL url = new
JMXServiceURL(“service:jmx:rmi:///jndi/rmi://localhost:9999/server”);
JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(url,
null, mbs);
System.out.println(“starting rmi connector server”);
server.start();
}
}
为了运行agent,首先在端口9999上进行RMI注册
c:\rmiregistry 9999 &
运行RemoteAgent类,当agent启动,你可以通过JConsole应用,像上一个例子一样。这次使用远程连接,所填内容如下:
service:jmx:rmi:///jndi/rmi://localhost:9999/server
如果你听过不同的connector的连接的话结果是一样的。connector提供一个透明的MBeanServer访问。
RemoteClient
现在还没有任何我们所关心的MBeans部署到server上。下一步就是通过MBeanServer用一个远程client部署和操作MBeans
package com.wisely.jmx;
import java.util.Iterator;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.QueryExp;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
public class RemoteClient {
MBeanServerConnection connection = null;
client端从创建一个和server一样的URL开始。然后远程连接到服务器上:
public RemoteClient() throws Exception {
JMXServiceURL url = new JMXServiceURL(
“service:jmx:rmi:///jndi/rmi://localhost:9999/server”);
JMXConnector connector = JMXConnectorFactory.connect(url);
connection = connector.getMBeanServerConnection();
}
通过连接接口,你可以操作被管理的资源。deploy方法创建3个worker。注意到:相同类型的对象可以部署到相同的服务器上只要ObjectName是唯一的。
void deploy() throws Exception {
connection.createMBean(“com.wisely.jmx.Worker”,
new ObjectName(“com.wisely.jmx:type=Worker,number=1”));
connection.createMBean(“com.wisely.jmx.Worker”,
new ObjectName(“com.wisely.jmx:type=Worker,number=2”));
connection.createMBean(“wrox.ch12.jmx.Worker”,
new ObjectName(“com.wisely.jmx:type=Worker,number=3”));
}
下一个方法,lookup(),是一个使用MBeanServer query接口的例子。这个query将会返回所有的部署在com.wisely.jmx domain上的所有Mbeans。通配符 *将会配准com.wisely.jmx domain下的所有字符
void lookup() throws Exception {
ObjectName on = new ObjectName(“com.wisely.jmx:*”);
Set set = connection.queryNames(on, null);
for (Iterator iter = set.iterator(); iter.hasNext();) {
ObjectName bean = (ObjectName) iter.next();
System.out.println(“deployed..=” + bean.toString());
}
}
void checkRunning() throws Exception {
ObjectName on = new ObjectName(“com.wisely.jmx:*”);
QueryExp exp = Query.eq(Query.attr(“Running”), Query.value(true));
Set set = connection.queryNames(on, exp);
for (Iterator iter = set.iterator(); iter.hasNext();) {
ObjectName bean = (ObjectName) iter.next();
System.out.println(“running.. MBean =” + bean.toString());
}
}
方法remove()是deploy的反操作--它移除符合一定标准的MBeans:
void remove() throws Exception {
ObjectName on = new ObjectName(“com.wisely.jmx:*”);
Set set = connection.queryNames(on, null);
for (Iterator iter = set.iterator(); iter.hasNext();) {
ObjectName bean = (ObjectName) iter.next();
System.out.println(“removing..=” + bean.toString());
connection.unregisterMBean(bean);
}
}
client也创建了一个标准的StringMonitor来跟踪一个MBean的属性:
public void addMonitor( ) throws Exception {
connection.createMBean(“javax.management.monitor.StringMonitor”, new
ObjectName(“wrox.ch12.jmx:name=WorkMonitor”));
}
public static void main(String[] args) throws Exception {
RemoteClient rc = new RemoteClient();
rc.remove();
rc.deploy();
rc.lookup();
rc.checkRunning();
rc.addMonitor();
}
}
现在client的部署已经完成。下面,你使用WorkMonitor来追踪WorkerMBean属性的变化。
WorkMonitor
通过管理控制台你可以看见并且可以发送属性在WorkMonitor,这样当属性变化的时候,就可以报告通知到控制台上。如图:
实现monitor的步骤如下:
1、增加你想要监控的WorkerMBean的objectName,使用addObservedObject()方法-在本例中是com.wisely.jmx:type=Worker,number=2.
2、设置你要监控的属性,通过OberservedAttribute()。现在正在监控Status属性。
3、下一步,设置StringToCompare属性,用来监控你想要监控的值
4、从属性列表上选择NotifyDiffer或者NotifyMatch
5、最后,激活start()操作开始监控
联系客服