专业的编程技术博客社区

网站首页 > 博客文章 正文

「进阶之路」揭开JMX的神秘面纱(jmx0)

baijin 2024-09-04 01:49:55 博客文章 6 ℃ 0 评论

No.1 相关概念

JMX(Java Management Extensions)是一个为应用程序植入管理功能的框架。JMX是一套标准的代理和服务,实际上,用户可以在任何Java应用程序中使用这些代理和服务实现管理。

JMX 要管理的对象是什么呢,是资源。

什么是资源,资源是指企业中的的各种应用软件和平台,举例来说,一个公司内部可能有许多应用服务器、若干 Web 服务器、一台或多台的数据库服务器及文件服务器等等,

那么,如果我们想监视数据库服务器的内存使用情况,或者我们想更改应用服务器上 JDBC 最大连接池的数目,但我们又不想重启数据库和应用服务器,这就是典型意义上的资源管理,

即对我们的资源进行监视 (Monitoring ,查看 ) 和管理 (Management ,更改 ) ,这种监视和更改不妨碍当前资源的正常运行。

对资源进行适当的监测和管理,可以让我们的 IT 资源尽可能的平稳运行,可以为我们的客户提供真正意思上的 24 × 7 服务。

在资源耗尽或者在硬件出故障之前,我们就可以通过管理工具监测到,并通过管理工具进行热调整和插拔。

应用场景:中间件软件WebLogic的管理页面就是基于JMX开发的,而JBoss则整个系统都基于JMX构架。

No.2 JMX架构

JMX的结构一共分为三层:

  • 基础层:主要是MBean,被管理的资源。
  • 代理层:MBeanServer,主要是提供对资源的注册和管理。
  • 管理层:提供远程访问的入口。

2.1、基础层(MBean)

该层包含 MBeans 及这些 MBeans 所管理的资源, MBeans 是一个 Java 对象,它必须实现 JMX 规范中规定的接口。

按照 JMX 规范,在 MBeans 对象的接口中,我们可以指定管理层可以访问资源的哪些属性,可以调用资源的哪些方法,并且,在资源的属性发生变化时,我们的 MBeans 可以发出消息,通知对这些属性变化感兴趣的其它对象。

JMX 规范定义了四种 MBeans ,它们分别是标准 MBeans(Standard MBeans) 、动态 MBeans(Dynamic MBeans) 、开放 MBeans(Open MBeans) 和模态 MBeans(Model MBeans) 。

  • 标准的MBean(Standard MBeans) Standard MBean这种类型的MBean最简单,它能管理的资源(包括属性,方法,时间)必须定义在接口中,然后MBean必须实现这个接口。它的命名也必须遵循一定的规范,例如我们的MBean为Hello,则接口必须为HelloMBean。 为了实现Standard MBean,必须遵循一套继承规范:
  • 必须为每一个MBean定义一个接口,且该接口名称必须=被管理的资源名+"MBean";
  • 该接口的实现类的名称必须是被管理的资源名;
  • 将它们注册到MBeanServer中

2.2、代理层(Agent)

代理层的目的就是要把 MBeans 中实现的接口暴露给管理层,该层通常由 MBean Server 和 Agent Services 构成。

  • MBean Server 就是一个 MBeans 对象注册器,所有的资源MBeans都注册到这个MBean Server,对象管理器或者其它的管理层应用程序可以通过访问MBean Server,
  • 从而可以访问 MBean Server中注册的MBeans,当然也就可以监视和管理和这些 MBeans 绑定的资源。


2.3、管理层(Manager)

又称之为分布式服务层 (Distributed Services) ,顾名思义,该层主要包含一些管理应用程序,这些程序可以访问和操作 JMX 代理层 (Agent Level) 。

No.3 示例程序

3.1、需求

在企业内部应用中,假设我们需要对应用所使用的数据库进行动态的切换(现实中应该没有这样的需求,这里只是为了举例),而且在切换过程中应用不能暂停服务,即必须保证7*24小时的运行。

3.2、设计

一般情况下,系统在切换数据库时,需要对数据库配置信息进行修改,然后重启服务,加载新的数据库配置信息。但是我们这里不能这样做,因为不能暂停服务。

那我们就使用JMX技术来实现吧。

3.3、编码

  • 编写数据库配置信息MBean接口
package io.xiaojl.jmx;
/** 
 * <p>Title: DBConfigMBean</p> 
 *
 * <p>Description: 数据库配置资源的接口类</p> 
 *
 * @author jilong.xiao 
 * @date 2018年9月11日 
 */
public interface DBConfigMBean {
 String getDriverClass();
 String getUrl();
 String getUsername();
 String getPassword();
 void setDriverClass(String driverClass);
 void setUrl(String url);
 void setUsername(String username);
 void setPassword(String password);
}
  • 编写接口实现类
package io.xiaojl.jmx;
/** 
 * <p>Title: DBConfig</p> 
 *
 * <p>Description: MBean(资源)</p> 
 *
 * @author jilong.xiao 
 * @date 2018年9月11日 
 */
public class DBConfig implements DBConfigMBean {
 private String driverClass;
 private String url;
 private String username;
 private String password;
 @Override
 public String getDriverClass() {
 return this.driverClass;
 }
 @Override
 public String getUrl() {
 return this.url;
 }
 @Override
 public String getUsername() {
 return this.username;
 }
 @Override
 public String getPassword() {
 return this.password;
 }
 @Override
 public void setDriverClass(String driverClass) {
 this.driverClass = driverClass;
 }
 @Override
 public void setUrl(String url) {
 this.url = url;
 }
 @Override
 public void setUsername(String username) {
 this.username = username;
 }
 @Override
 public void setPassword(String password) {
 this.password = password;
 }
}
  • 编写Agent类
package io.xiaojl.jmx;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.util.Iterator;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
/** 
 * <p>Title: DBConfigAgent</p> 
 *
 * <p>Description: 将MBean注册到MBeanServer</p> 
 *
 * @author jilong.xiao 
 * @date 2018年9月11日 
 */
public class DBConfigAgent {
 public static void main(String[] args) throws MalformedObjectNameException, 
 InstanceAlreadyExistsException, MBeanRegistrationException, 
 NotCompliantMBeanException, IOException {
 // 首先建立一个MBeanServer,MBeanServer用来管理我们的MBean,通常是通过MBeanServer来获取我们MBean的信息
 MBeanServer mbServer = ManagementFactory.getPlatformMBeanServer();
 String domainName = "OurMBean";
 ObjectName on = new ObjectName(domainName+":name=DBConfigMBean");
 //注册到MBeanServer
 DBConfigMBean dbConfigMBean = new DBConfig();
 mbServer.registerMBean(dbConfigMBean , on);
 System.out.println("---DBConfigMBean注册完成----");
 Set<ObjectInstance> beans = mbServer.queryMBeans(null, null);
 Iterator<ObjectInstance> it = beans.iterator();
 while(it.hasNext()){
 ObjectInstance next = it.next();
 ObjectName name = next.getObjectName();
 System.out.println("\t已经注册的MBean有:"+name);
 }
 //注册一个端口,绑定url后,客户端就可以使用rmi通过url方式来连接JMXConnectorServer 
 LocateRegistry.createRegistry(9001);
 String serviceURL = "service:jmx:rmi:///jndi/rmi://localhost:9001/jmxrmi";
 JMXServiceURL url = new JMXServiceURL(serviceURL);
 //创建JMXConnectorServer
 JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbServer); 
 //启动
 cs.start();
 System.out.println("---JMXConnectorServer启动完成----");
 }
}
  • 运行服务端
---OurMBean注册完成----
已经注册的MBean有:java.lang:type=OperatingSystem
已经注册的MBean有:java.lang:type=Compilation
已经注册的MBean有:java.lang:type=MemoryPool,name=PS Old Gen
已经注册的MBean有:JMImplementation:type=MBeanServerDelegate
已经注册的MBean有:java.lang:type=Memory
已经注册的MBean有:java.lang:type=MemoryPool,name=PS Perm Gen
已经注册的MBean有:java.lang:type=Runtime
已经注册的MBean有:java.nio:type=BufferPool,name=direct
已经注册的MBean有:java.lang:type=GarbageCollector,name=PS MarkSweep
已经注册的MBean有:java.nio:type=BufferPool,name=mapped
已经注册的MBean有:java.lang:type=Threading
已经注册的MBean有:java.lang:type=GarbageCollector,name=PS Scavenge
已经注册的MBean有:com.sun.management:type=HotSpotDiagnostic
已经注册的MBean有:java.lang:type=ClassLoading
已经注册的MBean有:java.lang:type=MemoryPool,name=PS Survivor Space
已经注册的MBean有:java.lang:type=MemoryManager,name=CodeCacheManager
已经注册的MBean有:java.lang:type=MemoryPool,name=Code Cache
已经注册的MBean有:java.lang:type=MemoryPool,name=PS Eden Space
已经注册的MBean有:java.util.logging:type=Logging
已经注册的MBean有:OurMBean:name=DBConfigMBean
---JMXConnectorServer启动完成----
  • 编写管理端
package io.xiaojl.jmx;
import java.io.IOException;
import java.util.List;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
/** 
 * <p>Title: JMXClient</p> 
 *
 * <p>Description: 客户端:可以获取jmx connector,并展示HelloMBean的一些信息,属性,及调用其方法</p> 
 *
 * @author jilong.xiao 
 * @date 2018年9月11日 
 */
public class JMXClient {
 static final String serviceURL = "service:jmx:rmi:///jndi/rmi://localhost:9001/jmxrmi";
 public static void main(String[] args) throws IOException, MalformedObjectNameException, 
 AttributeNotFoundException, InstanceNotFoundException, 
 MBeanException, ReflectionException {
 JMXServiceURL url = new JMXServiceURL(serviceURL);
 JMXConnector connect = JMXConnectorFactory.connect(url);
 MBeanServerConnection connection = connect.getMBeanServerConnection();
 System.out.println("获取MBeanServer中的所有Domain:");
 String[] domains = connection.getDomains();
 for(String domain:domains){
 System.out.println("\tdomain:"+domain);
 }
 String domainName = "OurMBean";
 ObjectName on = new ObjectName(domainName+":name=DBConfigMBean");
 System.out.println("设置"+on+"的相关资源:注意属性名称首字母大写");
 AttributeList attributes = new AttributeList();
 attributes.add(new Attribute("DriverClass", "com.mysql.jdbc.Driver"));
 attributes.add(new Attribute("Url", "jdbc:mysql://127.0.0.1:3306/xiaojldb"));
 attributes.add(new Attribute("Username", "root"));
 attributes.add(new Attribute("Password", "root"));
 connection.setAttributes(on, attributes);
 System.out.println("获取"+on+"的相关资源:");
 //Object driverClass = connection.getAttribute(on, "DriverClass");
 //System.out.println("\tdriverClass="+driverClass);
 String[] attnames = {"DriverClass","Url","Username","Password"};
 AttributeList attList = connection.getAttributes(on, attnames);
 List<Attribute> list = attList.asList();
 for(Attribute att: list){
 System.out.println("\t"+att.getName()+"="+att.getValue());
 }
 }
}
  • 运行管理端
获取MBeanServer中的所有Domain:
 domain:OurMBean
 domain:java.nio
 domain:JMImplementation
 domain:com.sun.management
 domain:java.lang
 domain:java.util.logging
设置OurMBean:name=DBConfigMBean的相关资源:注意属性名称首字母大写
获取OurMBean:name=DBConfigMBean的相关资源:
 DriverClass=com.mysql.jdbc.Driver
 Url=jdbc:mysql://127.0.0.1:3306/xiaojldb
 Username=root
 Password=root

原文作者:爱折腾的稻草

原文出处:GitShare

商业用途请与作者联系!

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表