使用JMX管理Spring Bean

本文围绕JMX(Java管理扩展)展开,介绍将Spring Bean导出为MBean的方法,可从命令行启动JConsole动态修改运行程序属性值。还阐述通过名称暴露方法的多种途径及处理MBean冲突的机制,最后讲解远程MBean的暴露与访问,包括配置注意事项。

JMX(Java Manage-ment Extensions)Java管理扩展:改变运行中应用的配置

一、将Spring Bean导出为MBean

    /**
     * 在Spring中声明一个 MBeanExporter, 将spittleController bean导出为一个模型MBean
     * @param spittleController
     * @return
     */
    @Bean
    public MBeanExporter mBeanExporter(SpittleController spittleController){
        MBeanExporter exporter = new MBeanExporter();
        Map<String, Object> beans = new HashMap<>();
        beans.put("spitter:name=SpittleController", spittleController);
        exporter.setBeans(beans);
        return exporter;
    }

从命令行启动JConsole:

使JDK在PATH上,然后输入jconsole 即可:

运行JConsole

进入之后,就可以动态修改正在运行中程序的属性值了:

动态修改运行程序中的属性值 

二、通过名称暴露方法

如果不做限制,所有public成员被导出为MBean的操作或属性,如下图:

导出所有的public成员

    /**
     * 在Spring中声明一个 MBeanExporter, 将spittleController bean导出为一个模型MBean
     * 同时配置 MBeanInfoAssembler , 限制某些方法将在MBean上暴露
     * @param spittleController
     * @return
     */
    @Bean
    public MBeanExporter mBeanExporter(SpittleController spittleController, MBeanInfoAssembler assembler){
        MBeanExporter exporter = new MBeanExporter();
        Map<String, Object> beans = new HashMap<>();
        beans.put("spitter:name=SpittleController", spittleController);
        exporter.setBeans(beans);
        exporter.setAssembler(assembler);
        return exporter;
    }

    /**
     * 通过名称暴露方法,限制哪些方法和属性将在MBean上暴露
     * @return
     */
    @Bean
    public MethodNameBasedMBeanInfoAssembler assembler(){
        MethodNameBasedMBeanInfoAssembler assembler =
                new MethodNameBasedMBeanInfoAssembler();
        assembler.setManagedMethods(new String[]{
                "getSpittlesPerPage","setSpittlesPerPage"
        });
        return assembler;
    }

配置MBean info assembler后的效果

除了上面这种方法外,还可以通过另外三种方法:配置MethodExclusionMBeanInfoAssembler、通过InterfaceBasedMBeanInfoAssembler接口、使用注解驱动的MBean。

注解的配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:mbean-export/>
</beans>

处理MBean冲突:

有三种机制: FAIL_ON_EXISTING、IGNORE_EXISTING、REPLACING_EXISTING

@Bean
    public MBeanExporter mBeanExporter(SpittleController spittleController, MBeanInfoAssembler assembler){
        MBeanExporter exporter = new MBeanExporter();
        Map<String, Object> beans = new HashMap<>();
        beans.put("spitter:name=SpittleController", spittleController);
        exporter.setBeans(beans);
        exporter.setAssembler(assembler);
        // 处理冲突
        exporter.setRegistrationPolicy(RegistrationPolicy.IGNORE_EXISTING);
        return exporter;
    }

三、远程MBean

3.1 暴露远程MBean

注意两点:一、配置RmiRegistryFactoryBean和配置ConnectorServerFactoryBean的顺序不能颠倒;二、端口不能为1099;

(关于第一点参考了:https://www.iteye.com/topic/358379

    /**
     * 通过RmiRegigstryFactoryBean来启动一个RMI注册表
     * @return
     */
    @Bean
    public RmiRegistryFactoryBean rmiRegistryFactoryBean(){
        RmiRegistryFactoryBean rmiRegistryFactoryBean = new RmiRegistryFactoryBean();
        rmiRegistryFactoryBean.setPort(1199);
        return rmiRegistryFactoryBean;
    }

    /**
     * 是MBean导为远程对象
     * 使用RMI远程访问
     * 将ConnectorServerFactoryBean
     * @return
     */
    @Bean
    public ConnectorServerFactoryBean connectorServerFactoryBean(){
        ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
        connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1199/spittle");
        /*try {
            connectorServerFactoryBean.setObjectName("connector:name=rmi");
        } catch (MalformedObjectNameException e) {
            throw new RuntimeException(e);
        }*/
        return connectorServerFactoryBean;
    }

3.2、 访问远程MBean

配置:

/**
 * @Date 2019-05-03
 * @Author lifei
 */
@Configuration
public class MBeanConfig {

    /**
     * 该bean用于访问基于RMI的远程服务器,它能够以MBeanServerConnection的形式注入到其他bean中
     * @return
     */
    @Bean
    public MBeanServerConnectionFactoryBean connectionFactoryBean(){
        MBeanServerConnectionFactoryBean mBeanServerConnectionFactoryBean =
                new MBeanServerConnectionFactoryBean();
        try {
            mBeanServerConnectionFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1199/spittle");
            return mBeanServerConnectionFactoryBean;
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
    }

}

操作:

/**
     * 获取属性值
     */
    @Test
    public void showSpittleName(){
        try {
            Object spittlesPerPage = mBeanServerConnection.getAttribute(new ObjectName("spitter:name=SpittleController"),
                    "SpittlesPerPage");
            System.out.println(spittlesPerPage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置值
     */
    @Test
    public void reSetSpittlesPerPage(){
        try {
            mBeanServerConnection.setAttribute(new ObjectName("spitter:name=SpittleController"),
                    new Attribute("SpittlesPerPage", 3));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通过调用方法设置值
     */
    @Test
    public void invokSetSpittlesPerPage(){
        try {
            mBeanServerConnection.invoke(new ObjectName("spitter:name=SpittleController"),
                    "setSpittlesPerPage", new Object[]{5}, new String[]{"int"});
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在按照《Spring  in Action》实践处理通知部分的时候:

监听通知部分没有实践出来

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值