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
商业用途请与作者联系!
本文暂时没有评论,来添加一个吧(●'◡'●)