Spring JMX编程学习(二)- 以Bean的方式注册MbeanServer

6 篇文章 1 订阅

系列文章目录

Java管理扩展JMX入门学习
Spring JMX编程学习(一)- 手动注册bean到MBeanServer
Spring JMX编程学习(二)- 以Bean的方式注册MbeanServer
Spring JMX编程学习(三)- 自定义JMX客户端
Spring JMX编程学习(四)- MBeans自动探测与注解
Spring JMX编程学习(五)- SpringBoot自动注册



前言

在上一章当中我们通过Spring中的org.springframework.jmx.export.MBeanExporter类将特定的Bean对象注册到MBeanServer中,通过源码分析,其实主要有以下两步,第一步是在MBeanExporter初始化的时候检查MBeanServer是否已经存在,不存在则创建一个,第二部是在所有非懒加载Bean初始化之后根据配置信息注册MBean到MBeanServer当中。其实在Spring当中也提供了其他配置MBeanServer的方式,本章我们就使用使用Bean配置MBeanServer的方式


提示:以下是本篇文章正文内容,依赖上一章的案例

一、添加MBeanServer配置

1. 注册mbeanServer

在spring-jmx-server.xml文件中添加mbeanServer并同时修改exporter并添加server属性引用。

<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean"/>

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
    <property name="beans">
        <map>
            <entry key="com.example.spring.jmx:name=testBean" value-ref="testBean"/>
        </map>
    </property>
    <property name="server" ref="mbeanServer"/>
</bean>

启动主类
在这里插入图片描述
但是通过JConsole无法查看到用户自定义的MBean信息
在这里插入图片描述

2. JConsole无法查看问题

使用了MBeanServerFactoryBean注册了之后,程序没有报错,但是通过JConsole却无法查看到用户自定义的MBean信息,这是怎么回事呢?分析一下MBeanServerFactoryBean的源码。
在这里插入图片描述
可以看到这个类继承了InitializingBean和FactoryBean两个接口,所以重点在afterPropertiesSet和getObject方法了。其中getObject方法只是简单返回server属性,重点就在afterPropertiesSet方法中,而这个方法就是给server赋值的。

private boolean locateExistingServerIfPossible = false;

@Nullable
private String agentId;

@Override
@Nullable
public MBeanServer getObject() {
	return this.server;
}

/**
 * Creates the {@code MBeanServer} instance.
 */
@Override
public void afterPropertiesSet() throws MBeanServerNotFoundException {
	// Try to locate existing MBeanServer, if desired.
	1. 是否使用已经存在的MBeanServer
	if (this.locateExistingServerIfPossible || this.agentId != null) {
		try {
			this.server = locateMBeanServer(this.agentId);
		}
		catch (MBeanServerNotFoundException ex) {
			// If agentId was specified, we were only supposed to locate that
			// specific MBeanServer; so let's bail if we can't find it.
			if (this.agentId != null) {
				throw ex;
			}
			logger.debug("No existing MBeanServer found - creating new one");
		}
	}

	2. server不存在则创建一个	
	// Create a new MBeanServer and register it, if desired.
	if (this.server == null) {
		this.server = createMBeanServer(this.defaultDomain, this.registerWithFactory);
		this.newlyRegistered = this.registerWithFactory;
	}
}

在afterPropertiesSet的主要逻辑分为两个部分,第一个是当locateExistingServerIfPossible属性设置为true或者agentId不为空的时候(默认情况下这两个条件都不满足);第二部分就是从第一部分没有获得server,此时调用createMBeanServer方法创建一个(传入的参数默认情况下分别为空和true)。

@Nullable
private String defaultDomain;

private boolean registerWithFactory = true;
/**
 * Create a new {@code MBeanServer} instance and register it with the
 * {@code MBeanServerFactory}, if desired.
 * @param defaultDomain the default domain, or {@code null} if none
 * @param registerWithFactory whether to register the {@code MBeanServer}
 * with the {@code MBeanServerFactory}
 * @see javax.management.MBeanServerFactory#createMBeanServer
 * @see javax.management.MBeanServerFactory#newMBeanServer
 */
protected MBeanServer createMBeanServer(@Nullable String defaultDomain, boolean registerWithFactory) {
	if (registerWithFactory) {
		return MBeanServerFactory.createMBeanServer(defaultDomain);
	}
	else {
		return MBeanServerFactory.newMBeanServer(defaultDomain);
	}
}

因此此时是通过MBeanServerFactory的createMBeanServer方法创建MBeanServer对象的。而我们之前使用的是ManagementFactory的getPlatformMBeanServer方法获取的,这两个方法有什么区别吗?
前者对应源码如下,通过源码不难发现,这个时候是不论之前是否存在MBeanServer实例,直接创建一个,而getPlatformMBeanServer方法则是如果不存在则创建(同样调用的是以下的createMBeanServer方法),存在的话则使用之前的实例,也就是说使用getPlatformMBeanServer一方面是存在重用的好处(单例),第二个还可以和Java平台公用MBeanServer。因为在我们引入的包中已经存在了不少的MBean,加载的过程中也会创建MBeanServer实例(我们上面JConsle可以查看的MBean就属于这一类了)。

private static final ArrayList<MBeanServer> mBeanServerList =
        new ArrayList<MBeanServer>();

public static MBeanServer createMBeanServer() {
    return createMBeanServer(null);
}

public static MBeanServer createMBeanServer(String domain)  {
   checkPermission("createMBeanServer");
   // 创建一个新的MBeanServer实例	
   final MBeanServer mBeanServer = newMBeanServer(domain);
   // 添加到MBeanServer实例列表当中
   addMBeanServer(mBeanServer);
   return mBeanServer;
}

private static synchronized void addMBeanServer(MBeanServer mbs) {
    mBeanServerList.add(mbs);
}

根据以上分析的结果,我们再次查看源码,在上面我们提到了如果locateExistingServerIfPossible属性设置为true的时候,就会走第一部分的逻辑,仔细体会这个属性名称的意思,查找已经存在的服务器,所以在bean配置时将这个属性设置为true.如下所示

<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
    <property name="locateExistingServerIfPossible" value="true"/>
</bean>

将此参数设置为true,此时会通过如下的方式加载MBeanServer,如果对上一章源码分析还有印象的话,应该会发现在MBeanExporter类型Bean初始化的时候也是调用的这个方法。

protected MBeanServer locateMBeanServer(@Nullable String agentId) throws MBeanServerNotFoundException {
	return JmxUtils.locateMBeanServer(agentId);
}

在这里插入图片描述
再次启动项目通过JConsole查看。如下所示,没有问题了。
在这里插入图片描述

总结

本章我们通过注册Bean的方式将MBeanServer加入到Spring的管理当中,同时也发现了其实MBeanServer对象不仅仅可以有一个,还可能有多个,除了通过locateExistingServerIfPossible设置重用已经存在的MBeanServer实例之外,还可以通过agentId进行明确的区分,在MBeanExporter中通过server属性明确注册到指定的MBeanServer当中。如果未指定任何服务器,则MBeanExporter会尝试自动检测正在运行的MBeanServer。这在大多数仅使用一个MBeanServer实例的环境中都有效,但是当存在多个实例时,MBeanExporter可能会选择错误的服务器。 在这种情况下,应使用MBeanServer agentId指示要使用的实例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lang20150928

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值