在Spring中,可以方便地集成JMX。

那么第一个问题来了:什么是JMX?

JMX是Java Management Extensions,它是一个Java平台的管理和监控接口。为什么要搞JMX呢?因为在所有的应用程序中,对运行中的程序进行监控都是非常重要的,Java应用程序也不例外。我们肯定希望知道Java应用程序当前的状态,例如,占用了多少内存,分配了多少内存,当前有多少活动线程,有多少休眠线程等等。如何获取这些信息呢?

为了标准化管理和监控,Java平台使用JMX作为管理和监控的标准接口,任何程序,只要按JMX规范访问这个接口,就可以获取所有管理与监控信息。

实际上,常用的运维监控如Zabbix、Nagios等工具对JVM本身的监控都是通过JMX获取的信息。

因为JMX是一个标准接口,不但可以用于管理JVM,还可以管理应用程序自身。下图是JMX的架构:

┌─────────┐ ┌─────────┐

│jconsole │ │ Web │

└─────────┘ └─────────┘

│ │

┌ ─ ─ ─ ─│─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─

JVM ▼ ▼ │

│ ┌─────────┐ ┌─────────┐

┌─┤Connector├──┤ Adaptor ├─┐ │

│ │ └─────────┘ └─────────┘ │

│ MBeanServer │ │

│ │ ┌──────┐┌──────┐┌──────┐ │

└─┤MBean1├┤MBean2├┤MBean3├─┘ │

│ └──────┘└──────┘└──────┘

─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘

JMX把所有被管理的资源都称为MBean(Managed Bean),这些MBean全部由MBeanServer管理,如果要访问MBean,可以通过MBeanServer对外提供的访问接口,例如通过RMI或HTTP访问。

注意到使用JMX不需要安装任何额外组件,也不需要第三方库,因为MBeanServer已经内置在JavaSE标准库中了。JavaSE还提供了一个jconsole程序,用于通过RMI连接到MBeanServer,这样就可以管理整个Java进程。

除了JVM会把自身的各种资源以MBean注册到JMX中,我们自己的配置、监控信息也可以作为MBean注册到JMX,这样,管理程序就可以直接控制我们暴露的MBean。因此,应用程序使用JMX,只需要两步:

编写MBean提供管理接口和监控数据;

注册MBean。

在Spring应用程序中,使用JMX只需要一步:

编写MBean提供管理接口和监控数据。

第二步注册的过程由Spring自动完成。我们以实际工程为例,首先在AppConfig中加上@EnableMBeanExport注解,告诉Spring自动注册MBean:

@Configuration

@ComponentScan

@EnableWebMvc

@EnableMBeanExport // 自动注册MBean

@EnableTransactionManagement

@PropertySource({ "classpath:/jdbc.properties" })

public class AppConfig {

...

}

剩下的全部工作就是编写MBean。我们以实际问题为例,假设我们希望给应用程序添加一个IP黑名单功能,凡是在黑名单中的IP禁止访问,传统的做法是定义一个配置文件,启动的时候读取:

# blacklist.txt

1.2.3.4

5.6.7.8

2.2.3.4

...

如果要修改黑名单怎么办?修改配置文件,然后重启应用程序。

但是每次都重启应用程序实在是太麻烦了,能不能不重启应用程序?可以自己写一个定时读取配置文件的功能,检测到文件改动时自动重新读取。

上述需求本质上是在应用程序运行期间对参数、配置等进行热更新并要求尽快生效。如果以JMX的方式实现,我们不必自己编写自动重新读取等任何代码,只需要提供一个符合JMX标准的MBean来存储配置即可。

还是以IP黑名单为例,JMX的MBean通常以MBean结尾,因此我们遵循标准命名规范,首先编写一个BlacklistMBean:

public class BlacklistMBean {

private Set ips = new HashSet<>();

public String[] getBlacklist() {

return ips.toArray(String[]::new);

}

public void addBlacklist(String ip) {

ips.add(ip);

}

public void removeBlacklist(String ip) {

ips.remove(ip);

}

public boolean shouldBlock(String ip) {

return ips.contains(ip);

}

}

这个MBean没什么特殊的,它的逻辑和普通Java类没有任何区别。

下一步,我们要使用JMX的客户端来实时热更新这个MBean,所以要给它加上一些注解,让Spring能根据注解自动把相关方法注册到MBeanServer中:

@Component

@ManagedResource(objectName = "sample:name=blacklist", description = "Blacklist of IP addresses")

public class BlacklistMBean {

private Set ips = new HashSet<>();

@ManagedAttribute(description = "Get IP addresses in blacklist")

public String[] getBlacklist() {

return ips.toArray(String[]::new);

}

@ManagedOperation

@ManagedOperationParameter(name = "ip", description = "Target IP address that will be added to blacklist")

public void addBlacklist(String ip) {

ips.add(ip);

}

@ManagedOperation

@ManagedOperationParameter(name = "ip", description = "Target IP address that will be removed from blacklist")

public void removeBlacklist(String ip) {

ips.remove(ip);

}

public boolean shouldBlock(String ip) {

return ips.contains(ip);

}

}

观察上述代码,BlacklistMBean首先是一个标准的Spring管理的Bean,其次,添加了@ManagedResource表示这是一个MBean,将要被注册到JMX。objectName指定了这个MBean的名字,通常以company:name=Xxx来分类MBean。

对于属性,使用@ManagedAttribute注解标注。上述MBean只有get属性,没有set属性,说明这是一个只读属性。

对于操作,使用@ManagedOperation注解标准。上述MBean定义了两个操作:addBlacklist()和removeBlacklist(),其他方法如shouldBlock()不会被暴露给JMX。

使用MBean和普通Bean是完全一样的。例如,我们在BlacklistInterceptor对IP进行黑名单拦截:

@Order(1)

@Component

public class BlacklistInterceptor implements HandlerInterceptor {

final Logger logger = LoggerFactory.getLogger(getClass());

@Autowired

BlacklistMBean blacklistMBean;

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

throws Exception {

String ip = request.getRemoteAddr();

logger.info("check ip address {}...", ip);

// 是否在黑名单中:

if (blacklistMBean.shouldBlock(ip)) {

logger.warn("will block ip {} for it is in blacklist.", ip);

// 发送403错误响应:

response.sendError(403);

return false;

}

return true;

}

}

下一步就是正常启动Web应用程序,不要关闭它,我们打开另一个命令行窗口,输入jconsole启动JavaSE自带的一个JMX客户端程序:

通过jconsole连接到一个Java进程最简单的方法是直接在Local Process中找到正在运行的AppConfig,点击Connect即可连接到我们当前正在运行的Web应用,在jconsole中可直接看到内存、CPU等资源的监控。

我们点击MBean,左侧按分类列出所有MBean,可以在java.lang查看内存等信息:

细心的童鞋可以看到HikariCP连接池也是通过JMX监控的。

在sample中可以看到我们自己的MBean,点击可查看属性blacklist:

点击Operations-addBlacklist,可以填入127.0.0.1并点击addBlacklist按钮,相当于jconsole通过JMX接口,调用了我们自己的BlacklistMBean的addBlacklist()方法,传入的参数就是填入的127.0.0.1:

再次查看属性blacklist,可以看到结果已经更新了:

我们可以在浏览器中测试一下黑名单功能是否已生效:

可见,127.0.0.1确实被添加到了黑名单,后台日志打印如下:

2020-06-06 20:22:12 INFO c.i.l.web.BlacklistInterceptor - check ip address 127.0.0.1...

2020-06-06 20:22:12 WARN c.i.l.web.BlacklistInterceptor - will block ip 127.0.0.1 for it is in blacklist.

注意:如果使用IPv6,那么需要把0:0:0:0:0:0:0:1这个本机地址加到黑名单。

如果从jconsole中调用removeBlacklist移除127.0.0.1,刷新浏览器可以看到又允许访问了。

使用jconsole直接通过Local Process连接JVM有个限制,就是jconsole和正在运行的JVM必须在同一台机器。如果要远程连接,首先要打开JMX端口。我们在启动AppConfig时,需要传入以下JVM启动参数:

-Dcom.sun.management.jmxremote.port=19999

-Dcom.sun.management.jmxremote.authenticate=false

-Dcom.sun.management.jmxremote.ssl=false

第一个参数表示在19999端口监听JMX连接,第二个和第三个参数表示无需验证,不使用SSL连接,在开发测试阶段比较方便,生产环境必须指定验证方式并启用SSL。详细参数可参考Oracle官方文档。这样jconsole可以用ip:19999的远程方式连接JMX。连接后的操作是完全一样的。

许多JavaEE服务器如JBoss的管理后台都是通过JMX提供管理接口,并由Web方式访问,对用户更加友好。

练习

编写一个MBean统计当前注册用户数量,并在jconsole中查看:

小结

在Spring中使用JMX需要:

通过@EnableMBeanExport启用自动注册MBean;

编写MBean并实现管理属性和管理操作。

java jmx教程_集成JMX相关推荐

  1. java jmx连接_使用JMX连接JVM

    什么是JMX? 什么是JMX,Java Management Extensions,即Java管理扩展,是一个为应用程序.设备.系统等植入管理功能的框架.JMX可以跨越一系列异构操作系统平台.系统体系 ...

  2. java核心教程_核心Java教程

    java核心教程 Welcome to Core Java Tutorial. I have written a lot on Core Java and Java EE frameworks. Th ...

  3. java高级教程_高级Java教程

    java高级教程 课程大纲 学习Java基础很容易. 但是,真正钻研该语言并研究其更高级的概念和细微差别将使您成为一名出色的Java开发人员. 网络上充斥着"软","便宜 ...

  4. java写作教程_如何编写技术教程-发布关于开发人员写作的新书

    java写作教程 Writing for Software Developers, a new book by Philip Kiely, teaches you everything that yo ...

  5. Java国际化教程_编程入门自学教程_菜鸟教程-免费教程分享

    教程简介 Java国际化入门教程 - 从简单的步骤了解Java国际化从基本到高级概念,包括概述,环境设置,区域设置,区域设置详细信息,显示语言,ResourceBundle,NumberFormat, ...

  6. Java Regex 教程_编程入门自学教程_菜鸟教程-免费教程分享

    教程简介 正则表达式不仅仅是Java的技术,在任何一门编程语言中都会存在,是一种通用的IT技术,其理念和用法在任何编程语言中基本一致,除了有一些由于语言不同而导致的一些语法不同正则表达式,主要用于匹配 ...

  7. java jmx 开启_开启JMX远程监控

    参考: 1. 启动参数java -server -Xms256M -Xmx256M -Xss256K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M ...

  8. jmx 替代_使用JMX作为Ganglia的现代替代品进行CLDB监视

    jmx 替代 有许多选项可用于监视MapR集群的性能和运行状况. 在本文中,我将介绍使用Java管理扩展(JMX)监视CLDB的鲜为人知的方法. 据最受尊敬的MapR数据工程师之一,Akihiko K ...

  9. javafx 教程_集成JavaFX和Swing

    javafx 教程 我刚刚完成了对使用Swing的应用程序组件的重写,现在使用的是JavaFX,最后得到了与更大的swing应用程序集成的JavaFX组件. 这是一个很大的应用程序,重写花了我一段时间 ...

最新文章

  1. 《Effective STL》学习笔记(第一部分)
  2. Django View使用装饰器捕获数据库连接异常
  3. OpenGL画简单图形
  4. 2019-05-22 防范ASP木马;如何防止注入攻击;
  5. 如何解决“请考虑使用 app.config 将程序集“XXXXXXXX”从版本XXXX重新映射到版本XXXX”的问题
  6. ProGuard的各种参数说明
  7. 镜像文件下载及VM部署win xp 保姆级教程
  8. c语言编辑游戏时用哪个软件,我想用C语言编写一个小型游戏,使用什么软件
  9. 02怎么学数据结构?
  10. 为什么牙齿上有白白的东西?
  11. 教你设置让电脑每天在指定时间自动关机
  12. Newtonsoft.Json.Linq 简单使用
  13. 计算机系的同学应该有更高的雄心壮志
  14. 回车符号和换行符号的区别
  15. 计算机软考职称属于哪个大类,计算机软考职称是什么
  16. 令人截图上瘾的录屏神器FSCapture
  17. 013 gtsam/examples/ISAM2Example_SmartFactor.cpp
  18. Flume之生产正确的使用方式一(Singel Agent)
  19. 国内人工智能行业全梳理
  20. 第五章 黎明踏浪号 Facebook (一)

热门文章

  1. make命令的参数选项(执行make时可以添加哪些选项)
  2. 区块链技术基础:术语和用例
  3. 爱驰汽车,用品质为梦想和情怀买单
  4. 计算机基础(27)——办公助手之电脑快捷键
  5. Share 远离驼背你可以更帅、更美
  6. django社交类程序笔记(14)社交模块模型创建
  7. 基于Apache的反向代理服务器
  8. leetcode 买卖股票
  9. Linux文件权限及用户权限总结
  10. 阿里首席技术官上传一份“面试Java面试小抄”,下载量突破百万