一、JMX最佳实践
1、Object Names(对象命名)
每个JMX MBean都需要一个“Object Name”,选择一个始终一致的、可用的Object Names将是非常重要的;客户端与你的对象模型(model)交互时,或许是直接将它展示且可读,比如jconsole;或者它被应用程序使用Object Names直接访问你声明的对象模型。所以,在多个models之间,MBean的对象命名一个尽可能唯一。
2、Object Name语法格式
一个Object Name是“javax.management.ObjectName”的实例,Object Name可以是一个MBean的名字,也可以是一个“表达式”、匹配多个MBeans名称。
它看起来像这样: “domain:key-property-list(关键属性列表)”,比如“com.demo.model:type=myType,name=myModel”。其中“domain”原则上可以为任意字符串,如果domain值为空,它将使用MBean Server的名称作为默认值;如果domain中包含“*”、“?”等正则表达式字符,这些字符串只能用来匹配(访问、查询、过滤)MBeans,不能用来声明一个MBean实例。此外domain不能包含“:”特殊字符,因为这是“domain”与“propery-list”的分隔符。
“key-property-list”有一个或者多个关键属性组成,格式为“key=value”,比如“type=Thread”;当多个properties是,它们之间以“,”分割,比如“name=DGC,type=Thread”;需要注意,空格是有意义的,我们不需要在“,”之后使用空格,比如“type=Thread, name=DGC”,那么“ name”将会被认为是属性名称。
此外,key的名称是有字符限制的,我们建议使用JAVA允许的、合法的标识符。value的字符也是有限制的,对于有些特殊字符,我们需要进行转义:ObjectName.quote;默认情况下,如果value是字符串(不是数字),我们应该总是转义它,除非我们能够确定它不会出现特殊字符。比如下述两个Object Names包含特殊字符(需要转义):
com.demo.myproject:type=Whatsit,name="25"
com.demo.myproject:type=Whatsit,name="25,26"
第二种情况,如果不转义将被认为是非法的。
对于表达式,“key-property-list”可以与上述的格式一样,也可以包含比如“*”、“?”甚至空字符串(与“*”等同),可以为“,*”结尾表示一个列表等。最终,这种格式用于匹配多个Object Names,它们具有指定的确切关键属性(如果有)、加上任何其他关键属性。比如“*:type=Thread,*”可以匹配“somedomain:type=Thread”、“somedomain:type=Thread,name=DGC”。
3、Object Name约定(规范)
1)一个MBean的Object Name应该是可以“预测的”,这意味着一个可以成为MBean的对象,我们应该能够知道它的Object Name将会什么。名称中不应该包含那些不是该对象固有部分的属性;此外,同一个对象的name不应该在application不同执行阶段而改变,比如不应该包含像“JVM进程ID”、“MBean Server ID”等这些每次执行会变化的属性。(“同一对象”的改变并不总是清晰或者有意义的,不过如果是这样,那么同一个对象始终具有相同的名称)
2)domain部分,应该以此对象的package名称作为前缀,以避免来自不同子系统(模块)所引入的冲突;比如:
com.demo.project1:type=Whatsit,name=5
org.demo.project2:typpe=Whatsit
domain不应该包含“/”,此字符串为MBean Server层次结构(级联)保留的,将会在后续版本中进行解释。
3)对于指定“type”的Object Name,应该包含相同的关键属性列表且它们具有相同的语法,且value具有相同语义。
如果在特定domain中,对于指定“type”的MBean只允许一个实例,那么它通常不再需要除“type”之外的、其他额外的属性。
如果同一“type”中可能有多个实例,它们可以通过使用不同的domain(即package名)或者其他关键属性来区分。大部分情况下,domain是一样的,我们通过使用不同的“name”属性值。
4)最常用的关键属性为:name和type。
通常“type=X,name=Y”组合属性对一个MBean命名就足够了;一些JMX感知的控制台能够使用比其他名称更容易阅读的简写形式来显示这种形式的名称。
有时候,我们也可以声明额外的属性,来满足上述种正则表达式匹配查询MBean的情况。比如“category”、“group”等。
4、Object containment(遏制)
有些托管对象(MBean)在逻辑上被其他托管对象所包含,这些对象或许无法独立存在。此时,下述模式是可行的。假如Server对象包含Application对象,Application包含WebModule对象,WebModule又包含Servlet;那么它们的名称看起来是这样的:
domain:type=Server,name=server5
domain:type=Server.Application,Server=server5,name=app1
domain:type=Server.Application.WebModule,Server=server5,Application=app1,name=module3
domain:type=Server.Application.WebModule.Servlet,Server=server5....WebModule=module3,name=servlet1
这种分层级的“type”属性可以让我们在不需要预知Model的前提下即可理解其他keys的含义;由于Object Name中key是无序的,因此无法知道例如在这里的第三个和第四个名称中,Application是否包含在Server中,反之亦然。这种模式意味着如果一个指定type的对象包含在其他type的对象中,那么它应该总是被包含。比如Server.Application总是包含在Server中。如果有其他Application没有包含在Server对象中,那么他们应该是不同的type,即事实上它们的type属性不应该为“Server.Application”;这与“特定type的MBean总是隐含相同key属性列表”的规则是一致的。
二、MBean介绍
MBean,即“managed bean”(托管的Bean),与普通的javaBean组件一样,只不过为JMX实现而设计;一个MBean可以表示一个“device”、“Application”或者任何需要被托管的资源。MBean可以暴露一些管理接口:
1)一系列可读、写的属性。(getter、setter)
2)一些可以被执行的operation。
3)自描述信息
管理接口,在MBean实例的整个生命周期中无法被修改;此外,MBean在遇到预定义的事件(events)发生时也可以触发通知(notification)。JMX实现中声明了5种MBean:
1)Standard MBeans
2)Dynamic MBeans
3)Open MBeans
4)Model MBeans
5)MXBeans
1、Standard MBeans(标准MBeans)是最常用的MBean,通常我们通过声明一个“SomethingMBean”样式的java接口、以及一个“Something”的类实现此接口的方式来创建一个MBean。此接口中方法用于声明一个属性或者操作,属性和操作的方法都遵循一定的设计规则。一个标准的MBean,由MBean接口和实现类组合而成;接口声明一系列暴露的属性和操作,实现类用于提供功能特性。
MBean接口
以HelloMBean为例:
package com.example; public interface HelloMBean { public void sayHello(); public int add(int x, int y); public String getName(); public int getCacheSize(); public void setCacheSize(int size); }
MBean接口采用其JAVA实现类的名称、并以“MBean”作为后缀。如示例,接口名为HelloMBean,那么其实现类为Hello。
根据JMX实现规范,一个MBean接口由可读写(readable、writable)的、命名化和类型化的属性,还有一些可以被Application调用的操作组成。HelloMBean接口表述了2个操作:add()和sayHello;2个属性:只读的name属性、可读写的cacheSize属性;getter和setter方法允许托管的Application访问或者修改属性的值。根据JMX实现,getter是任何public方法、返回值类型不是void、且其命名以get开头;getter允许manager读取属性值,返回值对象的类型即为属性的类型。setter是任何public方法、只包含一个参数、且其命名以set开头,setter允许manager写入属性的新值,其类型与参数类型一致。
MBean实现
public class Hello ... implements HelloMBean { public void sayHello() { System.out.println("hello, world"); } public int add(int x, int y) { return x + y; } public String getName() { return this.name; } public int getCacheSize() { return this.cacheSize; } public synchronized void setCacheSize(int size) { this.cacheSize = size; .... } }
创建JMX Agent来管理资源
一旦资源以MBean方式表达,那么该资源将有JMX Agent来管理。JMX Agent核心组件为MBean Server,MBean Server是一个托管对象用于MBean注册;JMX Agent还包含一些管理MBeans的服务。请参见MBean Server API。
import java.lang.management.*; import javax.management.*; public class Main { public static void main(String[] args) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("com.example:type=Hello"); Hello mbean = new Hello(); mbs.registerMBean(mbean, name); ... System.out.println("Waiting forever..."); Thread.sleep(Long.MAX_VALUE); } }
此main方法为示例,用于获取有Platform(通常为JVM平台、框架组件)已经创建或者初始化的MBean Server示例,通过调用getPlatformMBeanServer()方法。如果Platform尚未创建或者初始化MBean Server,那么此方法将会自动创建创建一个MBean Server实例(通过MBeanServerFactory.createMBeanServer,一旦创建此后即可公用)。
此后创建一个ObjectName实例,每个JMX MBean都必须有一个object name,其为ObjectName类型的实例,其命名语法必须符合JMX规范。即,必须包含一个domain和关键属性列表(K-V);通常domain为package名称,“type”为类名,“name”为资源名称。
创建一个Hello实例,并将其使用objectName注册到MBean Server中,通过MBeanServer.registerMBean()方法。注册之后,即可通过JMX 管理操作调用Hello实例的operation和属性。我们可以使用jconsole来演示MBean的属性获取和操作调用。
2、MXBeans
MXBean是一种特殊的MBean,它仅引用预定义数据类型。通过这种方式,你的MBean可以被任何Client使用,包括remote客户端,不需要访问表示此MBean的模型特定(model-specific)的类。MXBean提供了一种将相关值绑定在一起的便捷方式,无需客户端专门配置来处理绑定包。
与Standard MBean一样,MXBean的定义通过声明一个SomethingMXBean接口和一个实现类,不过MXBean的实现类的名称不需要必须为Something。MXBean中的每个方法声明一个属性或者操作。@MXBean注释也可以修饰在任何已有的JAVA接口上,从而不需要专门开发一个以“MXBean”为后缀的接口。
MXBean背后的主要思想是MXBean接口中引用的诸如“java.lang.management.MemoryUsage”之类的类型,比如“java.lang.management.MemoryMXBean”,映射成标准的类型,称为“Open Types”定义在“javax.management.openmbean”包中。具体的映射规则请参见MXBean规范实现。不过,通用原则是对于简单类型比如String、int等保持不变,对于复杂类型比如MemoryUsage类型将会映射成标准类型“CompositeDataSupport”。
有关MBean和MXBean的区别,请参考:https://docs.oracle.com/javase/8/docs/api/javax/management/MXBean.html
MXBean接口
package com.example; public interface QueueSamplerMXBean { public QueueSample getQueueSample(); public void clearQueue(); }
MXBean实现
package com.example; import java.util.Date; import java.util.Queue; public class QueueSampler implements QueueSamplerMXBean { private Queue<String> queue; public QueueSampler (Queue<String> queue) { this.queue = queue; } public QueueSample getQueueSample() { synchronized (queue) { return new QueueSample(new Date(), queue.size(), queue.peek()); } } public void clearQueue() { synchronized (queue) { queue.clear(); } } }
声明复杂类型
package com.example; import java.beans.ConstructorProperties; import java.util.Date; public class QueueSample { private final Date date; private final int size; private final String head; @ConstructorProperties({"date", "size", "head"}) public QueueSample(Date date, int size, String head) { this.date = date; this.size = size; this.head = head; } public Date getDate() { return date; } public int getSize() { return size; } public String getHead() { return head; } }
在QueueSample类中,MXBean框架通过所有的getter方法来将此实例转换为CompositeData实例(数组);(在反序列化时)使用@ConstructorProperties注释再从CompositeData实例中重建QueueSample实例。
JMX Agent中注册MXBean的方式与MBean一样,没有任何区别。
简单来说,如果你的MBean中的属性均为简单类型,用Standard MBean即可;如果有复杂类型,比如自定义的类,那么需要使用MXBean,并由CompositeData将复杂类型的属性进行转换。(复杂类型也是由JAVA的简单类型组合而成)。
JAVA已经内置了多个MXBean实现,可以帮助大家来学习JMX的相关技术。
1、BufferPoolMXBean:有关“direct”、“mapped” buffer的资源信息;如果Application为网络IO系统(比如Netty编程)、或者有大量文件操作,你应该考虑关注此MXBean。
2、ClassLoadingMXBean:有关JVM类加载相关的资源信息;如果Application为序列化相关的组件、脚本化集成组件、有较多代理类(包括动态加载,OSGI)等,你应该关注此MXBean。
3、GarbageCollectorMXBean:有关JVM GC相关的资源,包括GC时长、GC次数和相关内存状态。
4、MemoryPoolMXBean:有关JVM中“内存池”的相关资源信息,可以配合MemoryManagerMXBean一起使用。一个Application中可能有多个“内存池”实例,我们可以通过MemoryManagerMXBean获取内存池的列表,并查看此内存池的存量和GC相关信息。
5、OperatingSystemMXBean:有关操作系统的相关资源信息,比如CPU负载等。
6、PlatformManagedObject:内部接口,所有的JAVA平台有关的MXBean都扩展此接口,比如上述几个MXBean;通常应用程序不应该实现它。
7、RuntimeMXBean:有关runtime的信息,比如VM的参数、版本等。
8、ThreadMXBean:有关运行时线程状态的资源信息,比如“CPU高耗线程”、“死锁线程”等,可以帮助我们优化并发操作等。
三、JMX代码样例
我们可以参考很多开源组件的JMX实现,比如tomcat-jdbc等,如下示例仅供参考,我们建议JMX MBean注册、注销操作应该在MBean实现类中,此外也要求大家在开发组件时,尽量增加MBean信息托管,这对我们探测组件运行时状态数据非常有效,而且对监控良好。
/** * Description * <p> * </p> * DATE 17/12/9. * * @author liuguanqing. */ public class SlowQuery implements SlowQueryMXBean{ private String name; public SlowQuery() { } public SlowQuery(String name) { this.name = name; } protected void registerJmx() { try { MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); ObjectName objectName = getObjectName(); if(mBeanServer.isRegistered(objectName)) { return; } mBeanServer.registerMBean(this, objectName); } catch (MalformedObjectNameException e) { //ObjectName不合法时,建议统一ObjectName.quote(string) } catch (RuntimeOperationsException e) { //JMX operation操作异常时 } catch (MBeanException e) { //其他异常 } catch (InstanceAlreadyExistsException e) { //如果相同名称的MBean已注册 } catch (NotCompliantMBeanException e) { //如果MBean无法被JMX Agent无法兼容 } catch (Exception e) { // } } protected ObjectName getObjectName() throws Exception{ Class clazz = getClass(); if(name == null) { name = clazz.getSimpleName(); } return new ObjectName(clazz.getPackage().getName() + ":type=" + clazz.getSimpleName() + ",name=" + name); } protected void deRegisterJmx() { try { ManagementFactory.getPlatformMBeanServer().unregisterMBean(getObjectName()); } catch (MBeanRegistrationException e) { // } catch (InstanceNotFoundException e) { // } catch (MalformedObjectNameException e) { // } catch (RuntimeOperationsException e) { // } catch (Exception e) { // } } }
四、Spring与JMX(简述)
Spring中接入JMX的方式比较多,我们仅描述一种常用的、易于实施的方式。具体参见:Spring与JMX。
1、声明MBean,基于Spring注释
import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedOperationParameter; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.stereotype.Component; /** * Description * <p> * </p> * DATE 17/12/9. * * @author liuguanqing. */ //@ManagedResource(objectName = "com.demo.web.MyApp:type=HttpRequestGlobalInfo,name=httpRequestGlobal") @Component @ManagedResource public class HttpRequestGlobalInfo { private long totalRequestTimes;//请求总次数 private long avgResponseTime;//平均响应时间 @ManagedAttribute() public long getTotalRequestTimes() { return totalRequestTimes; } public void setTotalRequestTimes(long totalRequestTimes) { this.totalRequestTimes = totalRequestTimes; } @ManagedAttribute() public long getAvgResponseTime() { return avgResponseTime; } public void setAvgResponseTime(long avgResponseTime) { this.avgResponseTime = avgResponseTime; } @ManagedOperation public void reset(@ManagedOperationParameter(name = "all",description = "all")boolean all) { if(all) { totalRequestTimes = 0; } avgResponseTime = 0; } @ManagedOperation public void reset() { reset(false); } }
1)此Bean需要为SpringBean,我们可以通过@Component或者@Resource声明,当然你也可以在Spring.xml配置。
2)MBean上必须使用@ManagedResource注释,此后Spring将会通过代理 + 自动扫描的方式(配置注释驱动)来创建MBean实例以及注册到MBean Server。
ManagedResource注释中,可以声明objectName,此值建议遵循上述种JMX规范。如果不指定objectName和相关参数,那么将会采用“domain”(来自配置文件)作为域,“name”属性为SpringBean名称(默认值为类名简写,首字母小写,比如:httpRequestGlobalInfo)、“type”属性为“类名简写”(比如HttpRequestGlobalInfo)。
通常有两种选择:
A)你可以统一在spring.xml中指定domain,@ManagedResource中不再指定objectName;这种方式也利于remote Client来统一操作,因为这些MBean都在一个domain中。
B)你希望自定义domain(比如package名作为domain),那么你可以在@ManagedResource中指定objectName。(推荐方式)
3)@ManagedAttribute,声明在属性的getter或者setter方法上。主要是Spring与JMX Agent兼容(代理类)。
4)@ManagedOperation,声明在操作方法上,表示此方法问MBean的operation。(否则,只认为是普通的java方法,不会被export)
5)@ManagedOperationParameter,可以声明在operation的方法上,也可以声明在方法的参数上,用于表示此operation允许的参数列表。(代理类)
2、spring.xml配置
<bean id="jmxExporter" class="org.springframework.jmx.export.annotation.AnnotationMBeanExporter" lazy-init="false"> <!-- 需要人工注册的、非Spring实现的MBean,比如dataSource --> <property name="beans"> <map> <entry key="org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool" value="#{datasource.getPool().getJmxPool()}"/> </map> </property> <!-- 对于Spring注释驱动的MBean,将自动加载 --> <!-- 此处domain,仅供示例展示,通常建议在@ManagedResource中指定objectName --> <property name="defaultDomain" value="Application" /> </bean> <!-- 如果你没有开启Component-scan,那么你需要声明MBean作为springBean -->
3、JMX Agent
最常用的Agent就是jconsole工具,你可以运行此UI,查看MBean的所有信息。不过在Production环境中,或许remote端口无法访问,jconsole则无法使用,我们建议大家的WEB项目可以基于jolokia组件作为嵌入式的JMX Agent。接入jolokia也是非常简单,请参见:jolokia与Spirng JMX监控
文档参考:
1、JMX最佳实践:http://www.oracle.com/us/technologies/java/best-practices-jsp-136021.html
2、ObjectName:https://docs.oracle.com/javase/1.5.0/docs/api/javax/management/ObjectName.html
3、MBean介绍:https://docs.oracle.com/javase/tutorial/jmx/mbeans/index.html
4、JVM内部MXBean:https://docs.oracle.com/javase/8/docs/api/java/lang/management/package-summary.html
相关推荐
- **SNMP Manager API指南**:提供详细的API使用指南,包括示例代码和最佳实践建议。 #### 七、总结 JMX SNMP Manager API为开发者提供了一个强大的工具集,用于开发能够管理和监控基于JMX的应用程序的SNMP代理。...
7. **最佳实践**:分享如何有效利用JMX来优化和调试Java应用程序,避免常见的陷阱和误区。 总之,这个JMX资料包对于想要深入了解和利用JMX来提升Java服务器管理效率的人员来说,将是一份宝贵的资源。通过学习和实践...
本书深入介绍了Java Management Extensions(JMX)的核心概念、设计模式以及在实际应用中的最佳实践。以下是对本书各章节涉及的重要知识点的详细解读。 #### 第一部分:入门篇 ##### 1. 资源管理与JMX - **资源...
【描述】:“深入理解Java虚拟机:JVM高级特性与最佳实践(最新第二版)” 本书主要关注Java虚拟机(JVM)的高级特性和实践,涵盖了以下重要知识点: 1. **JVM架构**:理解JVM的内存模型,包括堆、栈、方法区、...
《ZooKeeper——分布式过程协同技术详解》这本书不仅介绍了ZooKeeper的基本概念和原理,还提供了许多实际案例和最佳实践,对于理解和使用ZooKeeper进行分布式应用的开发具有很高的参考价值。通过阅读这本书,读者...
**应用实例与最佳实践** 1. **监控Java应用程序**:通过JMX4Ant,开发者可以在构建过程中检查应用程序的状态,例如内存使用情况、线程数量等,确保应用程序的健康运行。 2. **自动化部署与配置**:利用JMX4Ant,可以...
5. **代码优化技巧**:书中会涵盖一系列编码最佳实践,如避免过度使用反射,减少不必要的类型转换,以及使用StringBuilder替代String进行字符串拼接,这些都可以显著提高代码执行效率。 6. **I/O与网络优化**:Java...
理解并发编程的基本原则和最佳实践是高级Java开发者的必备技能。 4. **IO与NIO**:Java的输入/输出系统是面试中的常见考点,包括流的分类、缓冲区的使用以及文件操作。NIO(非阻塞I/O)的引入为高性能服务器端程序...
WebLogic是Oracle公司的一款企业级Java应用服务器,它提供了运行和管理Java EE(Java Enterprise Edition)应用程序的平台。...同时,不断学习和跟进WebLogic的新特性和最佳实践,将使你在IT行业中保持竞争力。
同时,提供的文档如`weblogic.doc`和`EclipseWebLogic1.1.1.pdf`将提供更深入的指导,包括可能遇到的问题解决方案和最佳实践。 记住,配置过程可能会因Eclipse版本和WebLogic版本的不同而略有差异,所以根据实际...
8. **最佳实践** - 适当配置消费者的并发数,避免资源浪费和消息堆积。 - 注意消息的大小和数量,避免内存溢出。 - 根据业务场景选择合适的队列或主题模式。 通过以上内容,开发者应该能够理解ActiveMQ的基本...
10. 微服务技术:包括微服务架构的6个最佳实践,从微服务到服务网格、云原生的介绍,以及分布式缓存、Broker与Client消息模式、消息协议、消息QoS等。 11. 工具使用:需要熟练使用JDK内置命令行工具、JDK内置图形...
【深入剖析Tomcat——完整目录】 ...通过这份“深入剖析Tomcat”的完整目录,开发者可以从基础到高级,全方位掌握Tomcat的使用技巧和最佳实践,为构建稳定、高效、安全的Java Web应用打下坚实基础。
- **最佳实践**: - 分享配置优化、性能调优等方面的建议。 - 推荐一些高级特性如热部署、集群设置等的实现方法。 #### 六、结语 - **学习路径**: - 建议从基本概念开始,逐步深入到更复杂的主题。 - 强调...
8. **最佳实践与案例研究** - **实践经验**:分享作者在实际项目中应用ActiveMQ的经验和教训,给出最佳实践建议。 - **案例分析**:通过具体的业务场景,展示如何利用ActiveMQ解决实际问题。 通过阅读《ActiveMQ ...
《Zookeeper 3.4.8在Dubbo注册中心的应用详解》 Zookeeper,作为Apache的一个顶级项目,是一个分布式协调服务,它...在实际开发过程中,结合最佳实践,可以更好地发挥Zookeeper的功能,构建出高效、稳定的分布式系统。
《JMeter测试用例详解与应用实践》 Apache JMeter是一款强大的开源性能测试工具,广泛应用于Web应用、数据库和其他服务器的负载和压力测试。本文将深入解析“JmeterTestCases.zip”压缩包中的测试资源,旨在帮助...
10. **最佳实践**:分享在实际应用中使用ActiveMQ的一些最佳实践,包括性能调优、故障排查和日志分析等。 通过这15套视频教程,学习者不仅可以全面理解ActiveMQ的理论知识,还能通过实际操作提升解决问题的能力。...
【JBoss配置详解】 JBoss,全称Red Hat JBoss,是开源的Java应用服务器,由JBoss社区开发,现在隶属于Red Hat公司。...在实践中,务必注意文档更新、权限设置以及安全最佳实践,以确保JBoss环境稳定且安全地运行。