目录

  • 一、定义
  • 二、demo
  • 三、JMX在commons-pool2中的应用

一、定义

JMX(Java Management Extensions)

简单来说JMX技术提供了一套轻量的标准化的资源管理方式. 什么是资源的管理? 就是资源的增删改查!

使用JMX技术, 可以管理和监控Java虚拟机的资源(内存, CPU, 线程等). 也可以将符合规范的 Managed Bean(MBean) 对象注册到MBean服务器, MBean服务器作为JMX代理, 本地或者远程控制MBean.

JDK自带的jconsole工具就可以监控管理java应用中的MBean. jconsole工具位于%JAVA_HOME%\bin\目录下.

如果需要更准确更详细的了解JMX技术, 强烈建议阅读官方文档. 英文看起来吃力可以使用chrome浏览器, 右键翻译成中文.

二、demo

demo使用JMX实现在不重启应用的情况下, 动态修改对象的属性值. 该方法可以用于动态修改java应用中的配置.

demo目录

将MBean对象注册到MBeanServer中需要满足两个条件之一: 实现DynamicMBean接口 或者 自定义符合标准MBean规范的接口. demo中我们采用自定义MBean接口.

  1. 定义MBean接口AppConfigMBean. getB()表示B属性可读, setB()表示B属性可写. 这里暂时只测试一些基本类型.
package com.cztruth.jmx;
/**
* MBean接口规范, 详见 `com.sun.jmx.mbeanserver.Introspector.checkCompliance(Class<?>![](https://img2020.cnblogs.com/blog/2300815/202102/2300815-20210221223618559-1361345336.png)
mbeanClass)`
* e.g. 接口是`com.cztruth.jmx.AppConfigMBean`, 则实现类则是`com.cztruth.jmx.AppConfig`
*/
public interface AppConfigMBean {
/** A可读 */
int getA(); /** B可读 */
String getB(); /** B可写 */
void setB(String newB); /** C可读 */
int[] getC(); /** C可写 */
void setC(int[] newC);
}
  1. 实现MBean接口AppConfig.
package com.cztruth.jmx;

import java.util.Arrays;

/**
*
* 将自己实现的MBean注册到MBeanServer中需要满足以下两个条件之一:
* jdk中描述是`implement DynamicMBean, or follows the Standard MBean conventions`
* 1. 实现DynamicMBean接口.
* 2. 自定义MBean接口,接口必须符合标准的MBean规范. 详见`com.sun.jmx.mbeanserver.Introspector.checkCompliance(Class<?> mbeanClass)`
* e.g.`AppConfig`是`AppConfigMBean`的接口实现
*/
public class AppConfig implements AppConfigMBean { public int a; public String b; public int[] c; public AppConfig(int a, String b, int[] c) {
this.a = a;
this.b = b;
this.c = c;
} @Override
public int getA() {
return this.a;
} @Override
public String getB() {
return this.b;
} @Override
public void setB(String newB) {
this.b = newB;
} @Override
public int[] getC() {
return this.c;
} @Override
public void setC(int[] newC) {
this.c = newC;
} @Override
public String toString() {
return "AppConfig{" +
"a=" + a +
", b='" + b + '\'' +
", c=" + Arrays.toString(c) +
'}';
}
}
  1. Main.java中将一个AppConfig对象注册到MBeanServer. 并用while让程序一直运行, 这样做使应用可以被远程连接和管理. 这里要注意ObjectName的name需要符合ObjectName的命名规范.
package com.cztruth.jmx;

import javax.management.*;
import java.lang.management.ManagementFactory;
import java.text.SimpleDateFormat;
import java.util.Date; public class Main { /**
* 如果需要明确规定远程链接的端口, 需要在启动时加入以下jvm参数.
* e.g. java -jar -Dcom.sun.management.jmxremote.port=3333 -D... -D... jmx.jar.
* 如果使用的IDE工具启动项目需要去 Edit Configurations -> Configuration标签 -> VM options -> 添加 -D...
* -Dcom.sun.management.jmxremote.port=3333
* -Dcom.sun.management.jmxremote.ssl=false
* -Dcom.sun.management.jmxremote.authenticate=false
*/
public static void main(String[] args) { MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName = null;
AppConfig appConfig = new AppConfig(1, "sout", new int[]{45,33});
try {
// ObjectName的名字不能乱取, 需要遵守ObjectName的规范。 详见: `javax.management.ObjectName`注释
objectName = new ObjectName("com.cztruth.jmx.AppConfig:type=test,name=name1");
mBeanServer.registerMBean(appConfig, objectName);
/** 卡住线程, 并且每10s輸出一次 */
while (true) {
Thread.sleep(10000L);
System.out.print(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\t");
System.out.println(appConfig);
}
} 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();
} finally {
// 将AppConfig对象从MBeanServer中注销
if (objectName != null) {
try {
mBeanServer.unregisterMBean(objectName);
} catch (InstanceNotFoundException e) {
e.printStackTrace();
} catch (MBeanRegistrationException e) {
e.printStackTrace();
}
}
}
}
}
  1. 使用jconsole监控管理MBean.

运行demo(Main.java 下的 main())

找到并运行jconsole.exe. jconsole工具位于%JAVA_HOME%\bin\目录下. 博主的jconsole位于C:\Program Files\Java\jdk1.8.0_271\bin\jconsole.exe.

选择本地进程中的com.cztruth.jmx.Main进程.

MBean的标签下我们可以看到对应ObjectName(com.cztruth.jmx.AppConfig:type=test,name=name1). A, B, C三个属性值都是可读的.

通过jconsole, 修改该B的值为改好了, 并且控制台也正确输出了MBean对象的当前值已经被改动.

但是C属性却无法通过jconsole修改. 难道JMX无法管理数组? 理论上来说AppConfig对象只是持有的C数组的引用, String类型的B能被替换, C应该也是可以的. 而且 <<深入理解Java虚拟机>> 中提到过, 大部分bin目录下的工具都是jdk/lib/tools.jar的一层薄封装而已. 所以这里猜测jconsole只不过是没有将修改MBean数组属性的方式可视化操作. 之后查阅官方文档, 其中提到The JMX technology defines standard connectors (known as JMX connectors) that enable you to access JMX agents from remote management applications., 所以我们可以通过JMX connectors去远程控制MBean.

  1. UpdateAppConfig.java中就实现了自定义远程监控管理MBean.

运行demo(Main.java 下的 main()), 并且在启动时加入VM options, 设置JMX远程占用的端口号.

如果运行的是jar包启动, 则在控制台输入java -jar -Dcom.sun.management.jmxremote.port=3333 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false jmx.jar启动.

如果是在IDEA中则在启动设置的VM options参数中加上三个-D....

new一个JMXServiceURL对象, 因为demo运行时 jmxremote port 设置的是3333, 所以url = service:jmx:rmi:///jndi/rmi://localhost:3333/jmxrmi. 然后通过Attribute对象设置一个新的C.

package com.cztruth.jmx;

import javax.management.*;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Set; public class UpdateAppConfig { public static void main(String[] args) {
try {
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:3333/jmxrmi");
JMXConnector jmxConnector = JMXConnectorFactory.connect(jmxServiceURL);
MBeanServerConnection mBeanServerConnection = jmxConnector.getMBeanServerConnection();
// 查找所有的MBeans, 遍历就能获取所有的objectName
Set<ObjectInstance> set = mBeanServerConnection.queryMBeans(null,null);
for (ObjectInstance objectInstance : set) {
System.out.println(objectInstance.getObjectName().toString());
}
// 这里还是强制获取用作demo的 objectName
ObjectName objectName = new ObjectName("com.cztruth.jmx.AppConfig:type=test,name=name1");
// 修改 属性 C
Attribute cAttribute = new Attribute("C", new int[]{2,3,4,6});
mBeanServerConnection.setAttribute(objectName, cAttribute);
System.out.println();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ReflectionException e) {
e.printStackTrace();
} catch (InstanceNotFoundException e) {
e.printStackTrace();
} catch (MalformedObjectNameException e) {
e.printStackTrace();
} catch (AttributeNotFoundException e) {
e.printStackTrace();
} catch (InvalidAttributeValueException e) {
e.printStackTrace();
} catch (MBeanException e) {
e.printStackTrace();
} }
}

成功修改了C.

三、JMX在commons-pool2中的应用

在commons-pools中使用到了MXBean. 科普下 MXBean与MBean的区别

看完org.apache.commons.pool2.impl.GenericObjectPoolMXBean接口, 以及它的实现org.apache.commons.pool2.impl.GenericObjectPool, 推断出

它的作用就是监控pool的配置和pool中的对象. 接口中的Set<DefaultPooledObjectInfo> listAllObjects()方法就是为了监控pool中的对象.

我们使用一个测试用例, 将代码运行起来, 并往pool中添加三个对象, 借走其中一个. 然后使用jconsole工具监控.

package org.apache.commons.pool2.impl;

import org.junit.Test;

/**
* 当前测试需要在commons-pools的测试用力中的`rg.apache.commons.pool2.impl.TestGenericObjectPool`类完成.
* 当然也可以自己实现一个简单的PooledObjectFactory类.
*/
public class MyTest { private TestGenericObjectPool.SimpleFactory simpleFactory = null;
protected GenericObjectPool<String> genericObjectPool = null; @Test(timeout = 600000)
public void testJmxRegistration() {
try {
simpleFactory = new TestGenericObjectPool.SimpleFactory();
genericObjectPool = new GenericObjectPool<>(simpleFactory);
// 添加三个对象
genericObjectPool.addObject(); // "0"
genericObjectPool.addObject(); // "1"
genericObjectPool.addObject(); // "2"
// 10ms后借走一个对象
Thread.sleep(10L);
genericObjectPool.borrowObject();
} catch (Exception e) {
e.printStackTrace();
}
// 不要让线程结束
while (true) {
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

通过listAllObjects操作, 我们可以监控pool中的对象.

可以看到池子中有三个对象, 并且一个对象被借走一次.

感谢阅读!

【commons-pool2源码】_pre JMX的更多相关文章

  1. Apache Commons Pool2 源码分析 | Apache Commons Pool2 Source Code Analysis

    Apache Commons Pool实现了对象池的功能.定义了对象的生成.销毁.激活.钝化等操作及其状态转换,并提供几个默认的对象池实现.在讲述其实现原理前,先提一下其中有几个重要的对象: Pool ...

  2. 从源码角度看JedisPoolConfig参数配置

    做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 你好,JedisPoolConfig Java中使用Jedis作为连接Redis的工具.在使用Jedis的也可以配置Jed ...

  3. JAVA上百实例源码以及开源项目

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级.中级.高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情.执着,对IT的憧憬. ...

  4. JAVA上百实例源码网站

    JAVA源码包1JAVA源码包2JAVA源码包3JAVA源码包4 JAVA开源包1 JAVA开源包2 JAVA开源包3 JAVA开源包4 JAVA开源包5 JAVA开源包6 JAVA开源包7 JAVA ...

  5. commons.pool2 对象池的使用

    commons.pool2 对象池的使用 ? 1 2 3 4 5 <dependency>     <groupId>org.apache.commons</groupI ...

  6. ambari 2.5.0源码编译安装

    参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-bigdata-ambari/index.html Ambari 是什么 Ambar ...

  7. Spring框架之spring-web web源码完全解析

    Spring框架之spring-web web源码完全解析 spring-web是Spring webMVC的基础,由http.remoting.web三部分组成,核心为web模块.http模块封装了 ...

  8. 【commons-pool2源码】写前思考

    写作的初衷 工作4年多, 一直没有系统的阅读过优秀的开源代码, 所以从今年开始做一些尝试, 阅读源码并且试着将自己的理解以文章的形式输出, 从而达到以下目的: 通过阅读源码提升自身的技术水准, 通过写 ...

  9. 如何编译Zookeeper源码

    1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 2. 下载Zookeeper源码包 https://github.com/ap ...

随机推荐

  1. 将jekyll博客主页的超链接变为新标签页打开

    将jekyll博客主页的超链接变为新标签页打开 最近发现在打开博文查看时往往不想关闭当前页面,想新建一个页面打开,查了HTML资料以后进行修改 在根目录找到index.html,打开编辑,找到图示&l ...

  2. 和我一起理解js中的事件对象

    我们知道在JS中常用的事件有: 页面事件:load: 焦点事件:focus,blur: 鼠标事件:click,mouseout,mouseover,mousemove等: 键盘事件:keydown,k ...

  3. 【BFS】hdu 1973 Prime Path

    题目描述: http://poj.org/problem?id=3414 中文大意: 使用两个锅,盛取定量水. 两个锅的容量和目标水量由用户输入. 允许的操作有:灌满锅.倒光锅内的水.一个锅中的水倒入 ...

  4. Codeforces Round #656 (Div. 3) A. Three Pairwise Maximums

    题目链接:https://codeforces.com/contest/1385/problem/A 题意 给出三个正整数 $x,y,z$,找出三个正整数 $a,b,c$ 使得 $x = max(a, ...

  5. 【uva 247】Calling Circles(图论--Floyd 传递闭包+并查集 连通分量)

    题意:有N个人互相打了M次电话,请找出所有电话圈(Eg.a→b,b→c,c→d,d→a 就算一个电话圈)并输出.(N≤25,L≤25,注意输出格式) 解法:由于N比较小所有n^2或n^3的复杂度都没有 ...

  6. AcWing 241.楼兰图腾 (树状数组,逆序对)

    题意:在二维坐标轴上给你一些点,求出所有由三个点构成的v和∧图案的个数. 题解:因为给出的点是按横坐标的顺序给出的,所以我们可以先遍历然后求出某个点左边比它高和低的点的个数(这个过程简直和用树状数组求 ...

  7. Eclipse无法打开提示could not open jvm.cfg错误

    先言:我的问题只是出在之前我的java_jdk原来安装在F:\Temp这里,但是我之后在整理文件的时候把这个文件夹改成了F:\java_jdk.所以导致了错误的出现 解决方法1: 因为我的只是目录名称 ...

  8. 在WLS2下开发和部署NET Core3.1目录

    前言 在youtube推送上看到WSL2的消息(https://www.youtube.com/watch?v=MrZolfGm8Zk&t=1s),觉得很棒.恰好最近在学习PowerShell ...

  9. ApiPost V5 升级指南

    同旧版本相比,ApiPost V5 (以下简称V5)重新规划了底层架构,大大降低了内存使用率:并加入了大量新功能,用户体验也有了全新的提升.但是同旧版相比,很多使用方式有所不同,本文重点讲解以下用户升 ...

  10. k8s二进制部署 - etcd节点安装

    下载etcd [root@hdss7-12 ~]# useradd -s /sbin/nologin -M etcd [root@hdss7-12 ~]# cd /opt/src/ [root@hds ...