JMX和spring-boot-actuator入门
想学习下spring-boot-actuator, 发现需要前置技能: JMX; 重新温习下JMX,并且根据spring官网对actuator进行quickstart
spring-boot-actuator源码
https://cloud.tencent.com/developer/article/1892726
官方文档
JMX官方demo
https://docs.oracle.com/javase/8/docs/technotes/guides/jmx/examples.html
spring-boot-actuator官方文档
https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.enabling
学习代码仓库
JMX代码示例及文档
https://gitee.com/eeaters/hogwarts/tree/master/jmx/src/main/java/com/caicai/study/jmxv2/mbean
https://gitee.com/eeaters/hogwarts/tree/master/jmx/src/main/java/com/caicai/study/jmxv2/managementFactory
以前不完整的学习代码: https://gitee.com/eeaters/hogwarts/tree/master/jmx
sping-boot-actuator官方文档示例及文档
https://gitee.com/eeaters/hogwarts/tree/master/spring-module/actuator
spring-boot-actuator与JMX总结
个人总结为:
JMX( Java Management Extension)是java的标准的管理拓展规范 , 日常工作中常用的系统监控,如:内存,cpu使用率,线程数,垃圾回收等监控曲线都可以通过jmx来进行管理;并且可以运行时动态修改配置
spring-boot-actuator: 是spring对jmx进行拓展, 个人目前认为改善有两点
- MBean虽然有标准/动态/模型/开放四种创建方式,但是代码编写有一定门槛,经过spring的封装后,可以通过注解的形式(内部大部分是扩展了ModelMBean)来进行MBean的创建,
- 默认情况下服务会使用rmi协议进行通讯, 但是rmi协议是JAVA的轻量级RPC通讯框架,对于非JVM虚拟机上的服务通讯上受限制,而现在中性的通讯框架大都选择http进行通讯, spring-boot-actuator就在原有的基础上支持http协议,
在gitee的文档外进行一些补充
MBeanServer
使用代码 MBeanServer server = ManagementFactory.getPlatformMBeanServer();
创建一个MBeanServer时,默认恢将平台的默认组件添加进去, 诸如操作系统信息,类加载,jvm等信息都默认添加进去;
public static synchronized MBeanServer getPlatformMBeanServer() {
//...
if (platformMBeanServer == null) {
platformMBeanServer = MBeanServerFactory.createMBeanServer();
for (PlatformComponent pc : PlatformComponent.values()) {
List<? extends PlatformManagedObject> list =
pc.getMXBeans(pc.getMXBeanInterface());
for (PlatformManagedObject o : list) {
if (!platformMBeanServer.isRegistered(o.getObjectName())) {
addMXBean(platformMBeanServer, o);
}
}
}
//...
return platformMBeanServer;
}
enum PlatformComponent {
CLASS_LOADING("java.lang.management.ClassLoadingMXBean", "java.lang", "ClassLoading", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<ClassLoadingMXBean>() {
public List<ClassLoadingMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getClassLoadingMXBean());
}
}, new PlatformComponent[0]),
COMPILATION("java.lang.management.CompilationMXBean", "java.lang", "Compilation", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<CompilationMXBean>() {
public List<CompilationMXBean> getMXBeans() {
CompilationMXBean var1 = ManagementFactoryHelper.getCompilationMXBean();
return var1 == null ? Collections.emptyList() : Collections.singletonList(var1);
}
}, new PlatformComponent[0]),
MEMORY("java.lang.management.MemoryMXBean", "java.lang", "Memory", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<MemoryMXBean>() {
public List<MemoryMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getMemoryMXBean());
}
}, new PlatformComponent[0]),
GARBAGE_COLLECTOR("java.lang.management.GarbageCollectorMXBean", "java.lang", "GarbageCollector", keyProperties("name"), false, new PlatformComponent.MXBeanFetcher<GarbageCollectorMXBean>() {
public List<GarbageCollectorMXBean> getMXBeans() {
return ManagementFactoryHelper.getGarbageCollectorMXBeans();
}
}, new PlatformComponent[0]),
MEMORY_MANAGER("java.lang.management.MemoryManagerMXBean", "java.lang", "MemoryManager", keyProperties("name"), false, new PlatformComponent.MXBeanFetcher<MemoryManagerMXBean>() {
public List<MemoryManagerMXBean> getMXBeans() {
return ManagementFactoryHelper.getMemoryManagerMXBeans();
}
}, new PlatformComponent[]{GARBAGE_COLLECTOR}),
MEMORY_POOL("java.lang.management.MemoryPoolMXBean", "java.lang", "MemoryPool", keyProperties("name"), false, new PlatformComponent.MXBeanFetcher<MemoryPoolMXBean>() {
public List<MemoryPoolMXBean> getMXBeans() {
return ManagementFactoryHelper.getMemoryPoolMXBeans();
}
}, new PlatformComponent[0]),
OPERATING_SYSTEM("java.lang.management.OperatingSystemMXBean", "java.lang", "OperatingSystem", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<OperatingSystemMXBean>() {
public List<OperatingSystemMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getOperatingSystemMXBean());
}
}, new PlatformComponent[0]),
RUNTIME("java.lang.management.RuntimeMXBean", "java.lang", "Runtime", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<RuntimeMXBean>() {
public List<RuntimeMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getRuntimeMXBean());
}
}, new PlatformComponent[0]),
THREADING("java.lang.management.ThreadMXBean", "java.lang", "Threading", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<ThreadMXBean>() {
public List<ThreadMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getThreadMXBean());
}
}, new PlatformComponent[0]),
LOGGING("java.lang.management.PlatformLoggingMXBean", "java.util.logging", "Logging", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<PlatformLoggingMXBean>() {
public List<PlatformLoggingMXBean> getMXBeans() {
PlatformLoggingMXBean var1 = ManagementFactoryHelper.getPlatformLoggingMXBean();
return var1 == null ? Collections.emptyList() : Collections.singletonList(var1);
}
}, new PlatformComponent[0]),
BUFFER_POOL("java.lang.management.BufferPoolMXBean", "java.nio", "BufferPool", keyProperties("name"), false, new PlatformComponent.MXBeanFetcher<BufferPoolMXBean>() {
public List<BufferPoolMXBean> getMXBeans() {
return ManagementFactoryHelper.getBufferPoolMXBeans();
}
}, new PlatformComponent[0]),
SUN_GARBAGE_COLLECTOR("com.sun.management.GarbageCollectorMXBean", "java.lang", "GarbageCollector", keyProperties("name"), false, new PlatformComponent.MXBeanFetcher<com.sun.management.GarbageCollectorMXBean>() {
public List<com.sun.management.GarbageCollectorMXBean> getMXBeans() {
return PlatformComponent.getGcMXBeanList(com.sun.management.GarbageCollectorMXBean.class);
}
}, new PlatformComponent[0]),
SUN_OPERATING_SYSTEM("com.sun.management.OperatingSystemMXBean", "java.lang", "OperatingSystem", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<com.sun.management.OperatingSystemMXBean>() {
public List<com.sun.management.OperatingSystemMXBean> getMXBeans() {
return PlatformComponent.getOSMXBeanList(com.sun.management.OperatingSystemMXBean.class);
}
}, new PlatformComponent[0]),
SUN_UNIX_OPERATING_SYSTEM("com.sun.management.UnixOperatingSystemMXBean", "java.lang", "OperatingSystem", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<UnixOperatingSystemMXBean>() {
public List<UnixOperatingSystemMXBean> getMXBeans() {
return PlatformComponent.getOSMXBeanList(UnixOperatingSystemMXBean.class);
}
}, new PlatformComponent[0]),
HOTSPOT_DIAGNOSTIC("com.sun.management.HotSpotDiagnosticMXBean", "com.sun.management", "HotSpotDiagnostic", defaultKeyProperties(), true, new PlatformComponent.MXBeanFetcher<HotSpotDiagnosticMXBean>() {
public List<HotSpotDiagnosticMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getDiagnosticMXBean());
}
}, new PlatformComponent[0]);
JMXServiceURL
JMXServiceURL类的注释有详细描述了暴露接口的格式,
/**
* <p>The address of a JMX API connector server. Instances of this class
* are immutable.</p>
*
* <p>The address is an <em>Abstract Service URL</em> for SLP, as
* defined in RFC 2609 and amended by RFC 3111. It must look like
* this:</p>
*
* <blockquote>
*
* <code>service:jmx:<em>protocol</em>:<em>sap</em></code>
*
* </blockquote>
*
* <p>Here, <code><em>protocol</em></code> is the transport
* protocol to be used to connect to the connector server. It is
* a string of one or more ASCII characters, each of which is a
* letter, a digit, or one of the characters <code>+</code> or
* <code>-</code>. The first character must be a letter.
* Uppercase letters are converted into lowercase ones.</p>
*
* <p><code><em>sap</em></code> is the address at which the connector
* server is found. This address uses a subset of the syntax defined
* by RFC 2609 for IP-based protocols. It is a subset because the
* <code>user@host</code> syntax is not supported.</p>
*
* <p>The other syntaxes defined by RFC 2609 are not currently
* supported by this class.</p>
*
* <p>The supported syntax is:</p>
*
* <blockquote>
*
* <code>//<em>[host[</em>:<em>port]][url-path]</em></code>
*
* </blockquote>
*
* <p>Square brackets <code>[]</code> indicate optional parts of
* the address. Not all protocols will recognize all optional
* parts.</p>
*
* <p>The <code><em>host</em></code> is a host name, an IPv4 numeric
* host address, or an IPv6 numeric address enclosed in square
* brackets.</p>
*
* <p>The <code><em>port</em></code> is a decimal port number. 0
* means a default or anonymous port, depending on the protocol.</p>
*
* <p>The <code><em>host</em></code> and <code><em>port</em></code>
* can be omitted. The <code><em>port</em></code> cannot be supplied
* without a <code><em>host</em></code>.</p>
*
* <p>The <code><em>url-path</em></code>, if any, begins with a slash
* (<code>/</code>) or a semicolon (<code>;</code>) and continues to
* the end of the address. It can contain attributes using the
* semicolon syntax specified in RFC 2609. Those attributes are not
* parsed by this class and incorrect attribute syntax is not
* detected.</p>
*
* <p>Although it is legal according to RFC 2609 to have a
* <code><em>url-path</em></code> that begins with a semicolon, not
* all implementations of SLP allow it, so it is recommended to avoid
* that syntax.</p>
*
* <p>Case is not significant in the initial
* <code>service:jmx:<em>protocol</em></code> string or in the host
* part of the address. Depending on the protocol, case can be
* significant in the <code><em>url-path</em></code>.</p>
*
* @see <a
* href="http://www.ietf.org/rfc/rfc2609.txt">RFC 2609,
* "Service Templates and <code>Service:</code> Schemes"</a>
* @see <a
* href="http://www.ietf.org/rfc/rfc3111.txt">RFC 3111,
* "Service Location Protocol Modifications for IPv6"</a>
*
* @since 1.5
*/
public class JMXServiceURL implements Serializable {
}
rmi
rmi协议是java的轻量级的rpc协议,网上对此描述较多,定义可以自己查询,只是分析了下demo中的url;
首先jmx的规范服务url为: service:jmx:protocol:sap
,测试中是仿照网上的一篇博客编写, 直接对其进行简单的分析service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi
在JMXServiceURL构造参数中可以解析为:
- requiredPrefix: service:jmx -- 这部分是固定的,不能有任何修改
- protocol: rmi -- 协议: rmi协议
- host: "" --主机地址是空的,因为协议后面跟的不是ip地址,
- port: 0 -- host都为空,port不要想了
- urlPath: /jndi/rmi://localhost:9999/jmxrmi -- url路径
MBean
标准MBean/MXBean
- 对于标准MBean; 接口命名必须MBean为后缀,实现类就是接口去掉MBean
- 对于标准MBean ; 注意接口和实现类放在同一个包下; MXBean没有此限制
- MXBean使用接口方式对命名有限制,使用注解@MXBean则没有命名限制
ModelMBean
- 仿照的是spring中的MBean来编写demo, 目前看springboot中大都是模型MBean
OpenMbean
- 开放MBean,在一些spring对于rabbitmq/redis等提供支持时看到过部分使用; demo是基于硬编码的形式了解下openMBean的使用