使用JMX
JAVA Management Extensions的缩写,Java自带的一种管理资源的技术,比如对Java 应用程序,系统和网络等
java自带的获取各种信息的工具类
java自带的java.lang.management.ManagementFactory 可以看到它提供的一些列方法:
可以看到它提供了包括类加载、内存、线程等MXBean
以Memory为例,它包括两部分,MemoryMXBean和MemoryPoolMXBean
/**
* Returns the managed bean for the memory system of
* the Java virtual machine.
*
* @return a {@link MemoryMXBean} object for the Java virtual machine.
*/
public static MemoryMXBean getMemoryMXBean() {
return ManagementFactoryHelper.getMemoryMXBean();
}
MemoryMXBean提供获取堆内存和非堆内存的方法,返回对象MemoryUsage相应包含最大、已使用等信息
/**
* Returns the current memory usage of the heap that
* is used for object allocation. The heap consists
* of one or more memory pools. The <tt>used</tt>
* and <tt>committed</tt> size of the returned memory
* usage is the sum of those values of all heap memory pools
* whereas the <tt>init</tt> and <tt>max</tt> size of the
* returned memory usage represents the setting of the heap
* memory which may not be the sum of those of all heap
* memory pools.
* <p>
* The amount of used memory in the returned memory usage
* is the amount of memory occupied by both live objects
* and garbage objects that have not been collected, if any.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of <tt>MemoryUsage</tt> is
* <tt>CompositeData</tt> with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} object representing
* the heap memory usage.
*/
public MemoryUsage getHeapMemoryUsage();
/**
* Returns the current memory usage of non-heap memory that
* is used by the Java virtual machine.
* The non-heap memory consists of one or more memory pools.
* The <tt>used</tt> and <tt>committed</tt> size of the
* returned memory usage is the sum of those values of
* all non-heap memory pools whereas the <tt>init</tt>
* and <tt>max</tt> size of the returned memory usage
* represents the setting of the non-heap
* memory which may not be the sum of those of all non-heap
* memory pools.
*
* <p>
* <b>MBeanServer access</b>:<br>
* The mapped type of <tt>MemoryUsage</tt> is
* <tt>CompositeData</tt> with attributes as specified in
* {@link MemoryUsage#from MemoryUsage}.
*
* @return a {@link MemoryUsage} object representing
* the non-heap memory usage.
*/
public MemoryUsage getNonHeapMemoryUsage();
MemoryPoolMXBean能够获取 memory pool的名字,比如是否是Eden区,old区等等
/**
* Returns a list of {@link MemoryPoolMXBean} objects in the
* Java virtual machine.
* The Java virtual machine can have one or more memory pools.
* It may add or remove memory pools during execution.
*
* @return a list of <tt>MemoryPoolMXBean</tt> objects.
*
*/
public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() {
return ManagementFactoryHelper.getMemoryPoolMXBeans();
}
要获取整个的内存大小,需要使用Runtime
/**
* Returns the amount of free memory in the Java Virtual Machine.
* Calling the
* <code>gc</code> method may result in increasing the value returned
* by <code>freeMemory.</code>
*
* @return an approximation to the total amount of memory currently
* available for future allocated objects, measured in bytes.
*/
public native long freeMemory();
/**
* Returns the total amount of memory in the Java virtual machine.
* The value returned by this method may vary over time, depending on
* the host environment.
* <p>
* Note that the amount of memory required to hold an object of any
* given type may be implementation-dependent.
*
* @return the total amount of memory currently available for current
* and future objects, measured in bytes.
*/
public native long totalMemory();
/**
* Returns the maximum amount of memory that the Java virtual machine will
* attempt to use. If there is no inherent limit then the value {@link
* java.lang.Long#MAX_VALUE} will be returned. </p>
*
* @return the maximum amount of memory that the virtual machine will
* attempt to use, measured in bytes
* @since 1.4
*/
public native long maxMemory();
获取其它想要监控的信息
通过java.lang.management.ManagementFactory 获取 MBeanServer,平台所有的MBean都会注册到这个上面。然后通过获取ObjectName和属性就能获得值
JMX的架构
分成3块:Instrumentation,JMX agent和Remote management
- Instrumentation: 使用MBeans来实现资源检测(resources' instrumentation),MBeans有一套标准的规范,实现MBeans必须遵循,以实现标准化的处理
- JMX Agent: 用于直接的控制资源,并使得远程管理应用能够获取这些资源,它通常和控制的资源在同一台机器上。JMX Agent的核心组件是MBean server[]MBeans注册的地方]
- Remote management: JMX Agent实现的不同协议适配器和connector使得注册在MBean server上的MBeans都能够被看到,比如HTML的adaptor能够使得浏览器上能够展示MBean
MBean
一个MBean可以代表一个设备,应用或者任何可以被管理的资源。MBeans会暴漏具有如下特性的管理接口:
- 可读可写的属性集合:读对应着 get开头的方法,必须有返回值;写对应着set开头的方法
- 可调用操作的集合:自定义的一下方法
- 一段自我的描述
标准的MBeans
包含两个部分:MBean的接口和它的实现类。命名接口为 xxxMBean 。比如命名为 PaxiMBean,然后用一个java类 Paxi来实现这个接口。
MBean
package main.jmx;
public interface PaxiMBean {
void sayHi();
String getName();
void setName(String name);
}
Mbean实现
public class Paxi implements PaxiMBean {
@Override
public void sayHi() {
System.out.println("hi");
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name=name;
}
private String name="paxi";
}
Agent例子
package main.jmx;
public class MyAgent {
public static void main(String[] args) {
//1:获取平台已经创建并初始化的MBeanServer,没有就通过MBeanServerFactory.createMBeanServer()创建
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
//2:每个MBean必须有一个object name,name遵照标准格式
ObjectName name = new ObjectName("main.jmx:type=Paxi");
Paxi paxi = new Paxi();
//3:注册MBean
mbs.registerMBean(paxi,name);
System.out.println("wait for incoming request");
Thread.sleep(Long.MAX_VALUE);
} catch (MalformedObjectNameException e) {
e.printStackTrace();
} catch (NotCompliantMBeanException e) {
e.printStackTrace();
} catch (InstanceAlreadyExistsException e) {
e.printStackTrace();
} catch (MBeanRegistrationException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在命令行运行 jconsole,选中MBean,点击左侧栏 main.jmx
得到操作界面
点击sayHi,会弹窗提示调用成功
此时界面上会出现 sayHi的内容
wait for incoming request
hi
MXBeans
它是一种MBean的一种,仅用来引用一种预定义的数据类型。它的定义为 方式可以和MBean一样。接口后缀为MXBean然后在实现
public interface PaxiQMXBean {
PaxiQueue getPaxiQueue();
void clearQueue();
}
或者是使用MXBean的注解
@MXBean
public interface PaxiQInAnnotation {
PaxiQueue getPaxiQueue();
void clearQueue();
}
实现
public class PaxiQ implements PaxiQMXBean {
private Queue<String> queue;
public PaxiQ(Queue<String> queue) {
this.queue = queue;
}
@Override
public PaxiQueue getPaxiQueue() {
synchronized (queue){
return new PaxiQueue(new Date(),queue.size(),queue.peek());
}
}
@Override
public void clearQueue() {
synchronized (queue){
queue.clear();
}
}
}
其中的PaxiQueue是自己定义的一个对象
public class PaxiQueue {
private final Date date;
private final int size;
private final String head;
@ConstructorProperties({"date","size","head"})
public PaxiQueue(Date date, int size, String head) {
this.date = date;
this.size = size;
this.head = head;
}
public Date getDate() {
return date;
}
public String getHead() {
return head;
}
public int getSize() {
return size;
}
}
Agent的实现为
public class MyAgent {
public static void main(String[] args) {
//1:获取平台已经创建并初始化的MBeanServer,没有就通过MBeanServerFactory.createMBeanServer()创建
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
try {
ObjectName name = new ObjectName("main.jmx:type=PaxiQ");
Queue<String> queue = new ArrayBlockingQueue<String>(10);
queue.add("r-1");
queue.add("r-2");
queue.add("r-3");
PaxiQ mxbean = new PaxiQ(queue);
//3:注册MBean
mbs.registerMBean(mxbean,name);
System.out.println("wait for incoming request");
Thread.sleep(Long.MAX_VALUE);
} catch (MalformedObjectNameException e) {
e.printStackTrace();
} catch (NotCompliantMBeanException e) {
e.printStackTrace();
} catch (InstanceAlreadyExistsException e) {
e.printStackTrace();
} catch (MBeanRegistrationException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
启动后运行jconsole
可以看到自定义的属性值为CompositeDataSupport,双击它可以看到等他的内容:
但是如果PaxiQMXBean是一个MBean,即名字是PaxiQMBean,这个时候通过jconsole是无法找到的。
创建一个自己的JMX client
JMX client代码
public class PaxiClient {
public static void main(String[] args) {
System.out.println("create RMI client");
try {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxConnector = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
System.out.println("domains");
String[] domains= mBeanServerConnection.getDomains();
Arrays.sort(domains);
for (String domain:domains){
System.out.println(domain);
}
System.out.println("domain:"+mBeanServerConnection.getDefaultDomain());
System.out.println("MBean count:"+mBeanServerConnection.getMBeanCount());
Set<ObjectName> names = new TreeSet<ObjectName>(mBeanServerConnection.queryNames(null,null));
for (ObjectName name:names){
System.out.println("objectname:"+name);
}
ObjectName mbeanName = new ObjectName("main.jmx:type=Paxi");
PaxiMBean mbeanProxy = JMX.newMBeanProxy(mBeanServerConnection,mbeanName,PaxiMBean.class,true);
System.out.println("add notification listener..");
// 自定义消息的监听
PaxiClientListener listener = new PaxiClientListener();
mBeanServerConnection.addNotificationListener(mbeanName,listener,null,null);
mbeanProxy.setName("new name");
System.out.println("wait notifacaion");
TimeUnit.SECONDS.sleep(2);
System.out.println(mbeanProxy.getName());
mbeanProxy.sayHi();
TimeUnit.SECONDS.sleep(10);
jmxConnector.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (MalformedObjectNameException e) {
e.printStackTrace();
} catch (InstanceNotFoundException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
listener
public class PaxiClientListener implements NotificationListener{
@Override
public void handleNotification(Notification notification, Object handback) {
System.out.println("r notification");
System.out.println("class:"+notification.getClass().getName());
System.out.println("Source:"+notification.getSource());
System.out.println("Type:"+notification.getType());
System.out.println("Message:"+notification.getMessage());
if (notification instanceof AttributeChangeNotification){
AttributeChangeNotification n= (AttributeChangeNotification) notification;
System.out.println("attr name:"+n.getAttributeName());
System.out.println("attr type:"+n.getAttributeType());
System.out.println("attr new Value:"+n.getNewValue());
System.out.println("attr old Value:"+n.getOldValue());
}
}
}