MBean与JMX
欢迎查看Eetal的第二十二篇博客–MBean与JMX
JMX
JMX(java Management Exetensions)在Java编程语言中定义了应用程序以及网络管理和监控的体系结构、设计模式、应用程序接口以及服务。
通常使用JMX来监控系统的运行状态或管理系统的某些方面,比如清空缓存、重新加载配置文件等
优点是可以非常容易的使应用程序被管理
伸缩性的架构使每个JMX Agent Service可以很容易的放入到Agent中,每个JMX的实现都提供几个核心的Agent Service,你也可以自己编写服务,服务可以很容易的部署,取消部署。
主要作用是提供接口,允许有不同的实现
简单来说,jmx是一个用来管理javaBean并可以进行监控的扩展规范,结合MBeanServer、rmi与http等可以作为一个服务监控和提供中心
MBeanServer
MBeanServer是JMX代理的核心组件。
它是在代理中向管理操作公开的对象的注册表。
向MBeanServer注册的任何对象都对管理应用程序可见。
MBeanServer仅公开MBean的管理接口,而不是它的直接对象引用。
您要从代理的Java VM外部管理的任何资源都必须在MBeanServer中注册为MBean。
MBeanServer还提供标准化接口,用于访问同一Java VM中的MBean,为本地对象提供操作可管理资源的所有好处。
需要注意的是,一般不使用MBeanServerFactory.createMBeanServer(),使用ManagementFactory.getPlatformMBeanServer()
后者在当前尚未在ManagementFactory中注册静态成员MBeanServer时,会先使用MBeanServerFactory.createMBeanServer()创建一个MBeanServer并将其注册到静态成员,后续每次调用会直接返回该成员实例
并且ManagementFactory.getPlatformMBeanServer()方法在第一次调用createMBeanServer()实例化MBeanServer以后,会读取PlatformComponent枚举的枚举值,将一些系统必要的MBean注册到MBeanServer
JConsole监控的MBeanServer就是在ManagementFactory中注册的静态成员MBeanServe
所以如果没有特殊配置的MBeanServer,jconsole是不会监控的
Agent
Java Management Extensions(JMX)Agent是一个在Java虚拟机(Java VM)中运行的管理实体.
充当MBean和管理应用程序(JConsole等)之间的联络人
Agent只是一个规范,一般会封装我们创建和启动MBeanServer以及注册MBean的过程在一个Agent行为里,方便启动
Agent Service
Agent Service是可以对MBeanServer中注册的MBean执行管理操作的对象。
通过将管理智能包含在代理中,JMX可帮助您构建更强大的管理解决方案。
Agent Service通常也是MBean,允许通过MBeanServer控制它们及其功能。
JMX规范定义了以下Agent Service:
通过管理applet(m-let)服务的动态类加载检索并实例化从网络动态下载的新类和本机库。
监视器观察MBean属性的数字或字符串值,并可以向其他对象通知几种类型的更改。
定时器提供调度机制,并且可以以预定间隔发送通知。
关系服务定义MBean之间的关联并维护关系的一致性。
Protocol Adaptors and Connectors
Protocol adaptors and connectors使代理可从远程(通过rmi或者http等协议)管理应用程序访问。
它们通过在MBean服务器中实例化和注册的MBean的特定协议提供视图。
它们使Java VM外部的管理应用程序能够:
获取或设置现有MBean的属性
对现有MBean执行操作
实例化并注册新的MBean
注册并接收MBean发出的通知
因此,要使JMX代理易于管理,它必须至少包含一个协议适配器或连接器。
Java SE平台包括标准RMI连接器。Agent可以包括任意数量的协议适配器和连接器,允许通过不同的协议同时远程管理和监视它
Protocol Adaptors
Protocol Adaptors通过给定协议提供JMX代理的管理视图。
它们将MBean和MBean服务器的操作调整为给定协议中的表示,
并可能调整为不同的信息模型,例如SNMP。Java SE平台不包括任何协议适配器作为标准。
连接到Protocol Adaptors的管理应用程序通常特定于给定的协议。
这通常是依赖于特定管理协议的传统管理解决方案的情况。
它们不是通过MBean服务器的远程表示来访问JMX代理,而是通过映射到MBeanServer的操作来访问JMX代理。
Connectors
Connectors用于将代理与为JMX技术启用的远程管理应用程序连接,即使用JMX规范的分布式服务开发的管理应用程序。
这种通信涉及Agent中的连接器服务器和管理器中的连接器客户端。
这些组件以特定协议的方式透明地传递管理操作。
JMX Remote API为MBeanServer提供远程接口,管理应用程序可以通过该接口执行操作。
Connectors特定于给定协议,但管理应用程序可以无差别地使用任何Connectors,因为它们具有相同的远程接口。
MBean
描述一个可管理的资源。是一个java对象,遵循以下一些规则:
1.必须是公用的,非抽象的类
2.必须有至少一个公用的构造器
3.必须实现它自己的相应的MBean接口或者实现javax.management.DynamicMBean接口
4.可选的,一个MBean可以实现javax.management.NotificationBroadcaster接口MBean的类型
MBean使用ObjectName以keyValue形式注册到MBeanServer上
Standard MBean
标准MBean,也是最简单的MBean,通过类实现的接口名称来识别MBean
接口名称以MBean结尾,实现类需要匹配接口名称的前半部分
public interface YytMBean{
public void setName(String name);
public String getName();
}
public class Yyt implements YytMBean{
private String name;
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
public class YytAgent{
private String domainName;
private int rmiPort;
public YytAgent(String domainName,int rmiPort) {
this.domainName = domainName;
this.rmiPort = rmiPort;
}
public void start() throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, IOException {
//MBeanServerFactory.createMBeanServer(); //don't use this
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); //use this instead
YytMBean yytMBean = new Yyt();
ObjectName objectName = new ObjectName(domainName+":name=Yyt");
mBeanServer.registerMBean(yytMBean, objectName);
LocateRegistry.createRegistry(rmiPort);//开启rmi端口监听,在jmxConnectorServer.start()时会根据serviceUrl建立一个rmiServer监听该rmi端口
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:"+rmiPort+"/"+domainName);
JMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, null, mBeanServer);
jmxConnectorServer.start();
//开启jmx协议的监控服务器,因为java自带rmi的工具和依赖,可以直接开启,通过jconsole等支持jmx协议的客户端可以监控MBeanServer
}
}
使用JConsole工具监控
JConsole是java自带的监控程序,独立jre中没有,jdk下的jre具备
运行java应用时带上参数
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
关闭ssl和密码校验,开启远程监控端口8999,这时可以直接使用jconsole进行链接
或者在jdk\jre\lib\management目录下,复制一份jmxremote.password.template的文件,改名去掉.template后缀,并去掉文件末尾两行示例的用户名和密码注释,修改密码为自己想要的
运行加上参数
-Djava.rmi.server.hostname=应用所在服务器的ip或者域名
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=监控端口
-Dcom.sun.management.jmxremote.rmi.port=rmi监控端口(一般与监控端口保持一致)
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=false
这时使用JConsole链接会提示需要输入用户名和密码
在命令行输入jconsole运行jconsole程序
]
在jconsole的界面,因为是本地,直接选择本地进程,进入监控页面
点击导航栏的MBean即可看到我们注册的MBean在列表中
还可以对Bean的属性值进行查看和设置
]
源码分析
ManagementFactory.getPlatformMBeanServer()
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm = new MBeanServerPermission("createMBeanServer");
sm.checkPermission(perm);
}
if (platformMBeanServer == null) {
platformMBeanServer = MBeanServerFactory.createMBeanServer();
for (PlatformComponent pc : PlatformComponent.values()) {
List<? extends PlatformManagedObject> list =
pc.getMXBeans(pc.getMXBeanInterface());
for (PlatformManagedObject o : list) {
// Each PlatformComponent represents one management
// interface. Some MXBean may extend another one.
// The MXBean instances for one platform component
// (returned by pc.getMXBeans()) might be also
// the MXBean instances for another platform component.
// e.g. com.sun.management.GarbageCollectorMXBean
//
// So need to check if an MXBean instance is registered
// before registering into the platform MBeanServer
if (!platformMBeanServer.isRegistered(o.getObjectName())) {
addMXBean(platformMBeanServer, o);
}
}
}
HashMap<ObjectName, DynamicMBean> dynmbeans =
ManagementFactoryHelper.getPlatformDynamicMBeans();
for (Map.Entry<ObjectName, DynamicMBean> e : dynmbeans.entrySet()) {
addDynamicMBean(platformMBeanServer, e.getValue(), e.getKey());
}
for (final PlatformManagedObject o :
ExtendedPlatformComponent.getMXBeans()) {
if (!platformMBeanServer.isRegistered(o.getObjectName())) {
addMXBean(platformMBeanServer, o);
}
}
}
return platformMBeanServer;
ManagementFactory中定义一个platformMBeanServer成员来装载创建好的MBeanServer
在执行该方法的第一步会先校验当前安全权限
在platformMBeanServer尚未绑定一个实例时,会先使用MBeanServerFactory.createMBeanServer()实例一个MBeanServer对象
接下来主要是读取PlatformComponent.values()以及别的枚举类和helper类的值和成员,将系统预设的MBean注册到MBeanServer
enum PlatformComponent {
/**
* Class loading system of the Java virtual machine.
*/
CLASS_LOADING(
"java.lang.management.ClassLoadingMXBean",
"java.lang", "ClassLoading", defaultKeyProperties(),
true, // singleton
new MXBeanFetcher<ClassLoadingMXBean>() {
public List<ClassLoadingMXBean> getMXBeans() {
return Collections.singletonList(ManagementFactoryHelper.getClassLoadingMXBean());
}
}),
/**
* Compilation system of the Java virtual machine.
*/
COMPILATION(
"java.lang.management.CompilationMXBean",
"java.lang", "Compilation", defaultKeyProperties(),
true, // singleton
new MXBeanFetcher<CompilationMXBean>() {
public List<CompilationMXBean> getMXBeans() {
CompilationMXBean m = ManagementFactoryHelper.getCompilationMXBean();
if (m == null) {
return Collections.emptyList();
} else {
return Collections.singletonList(m);
}
}
}),
.....
}
MBeanServerFactory.createMBeanServer()
public static MBeanServer createMBeanServer() {
return createMBeanServer(null);
}
public static MBeanServer createMBeanServer(String domain)