使用MBean和Jolokia實現數據監控

靜態MBean的定義

通過MBean的定義可以在系統運行時,查看系統內部的數據或執行系統內部的功能,真正的使用過程中靜態MBean的使用是最多的。

定義的MBean必須實現以類名+MBean的接口

如下所示定義了一個MBean結構ShardInfo,所以爲了使ShardInfo能夠註冊進MBeanServer中,需要定義接口ShardInfoMBean,並實現。

@Getter
@Setter
public class ShardInfo extends AbstractMXBean implements ShardInfoMBean {
    private String shardName;
    protected ShardInfo(String mBeanName, String mBeanType, String mBeanCategory) {
        super(mBeanName, mBeanType, mBeanCategory);
    }
}

mBeanName/mBeanType/mBeanCategory主要是對MBean進行分類,對應效果如圖:
在這裏插入圖片描述

實現的XXMBean接口中,以getXX方法確定可以查詢的字段

public interface ShardInfoMBean {
    String getShardName();
}

如上面代碼所示,顯示的字段爲shardName。
在這裏插入圖片描述

可以觸發方法,也是XXMBean接口中定義的方法,實現即爲MBean中對應的實現

新增printShardName方法與實現

public interface ShardInfoMBean {
    String getShardName();

    void printShardName();
}
    @Override
    public void printShardName() {
        System.out.println("ShardName:" + shardName);
    }

在這裏插入圖片描述
手動觸發該方法:
在這裏插入圖片描述
方法執行完成:
在這裏插入圖片描述

MBean註冊

從上文已經知道對於靜態MBean如何定義,通過JDK自帶的ManagementFactory可以完成MBean的註冊。核心邏輯如下所示:

    private boolean registerMBean() {
        boolean registered = false;
        try {
            // Object to identify MBean
            final ObjectName mbeanName = this.getMBeanObjectName();
            log.debug("Register MBean {}", mbeanName);
            // unregistered if already registered
            if (server.isRegistered(mbeanName)) {
                log.debug("MBean {} found to be already registered", mbeanName);
                try {
                    unregisterMBean(mbeanName);
                } catch (Exception e) {
                    log.warn("unregister mbean {} resulted in exception {} ", mbeanName, e);
                }
            }
            server.registerMBean(this, mbeanName);
            registered = true;
            log.debug("MBean {} registered successfully", mbeanName.getCanonicalName());
        } catch (Exception e) {
            log.error("registration failed.", e);
        }
        return registered;
    }

其中server是固定的:

private final MBeanServer server = ManagementFactory.getPlatformMBeanServer();

mbeanName全路徑名稱格式爲BASE_JMX_PREFIX:type=XX,catagory=XX,name=XX具體拼接代碼爲:

    private ObjectName getMBeanObjectName() throws MalformedObjectNameException {
        StringBuilder builder = new StringBuilder(BASE_JMX_PREFIX)
                .append("type=").append(getMBeanType());

        if (getMBeanCategory() != null) {
            builder.append(",Category=").append(getMBeanCategory());
        }

        builder.append(",name=").append(getMBeanName());
        return new ObjectName(builder.toString());
    }

使用代碼查詢MBean屬性與執行方法

    MBeanServer server = ManagementFactory.getPlatformMBeanServer();

    @Test
    public void testGetShardInfoMBean() throws MalformedObjectNameException, IntrospectionException, InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException {
        ShardInfo shardInfo = new ShardInfo("sharInfo", "shard", "category1");
        shardInfo.setShardName("sunquan");
        shardInfo.register();
        MBeanInfo mBeanInfo = server.getMBeanInfo(shardInfo.getMBeanObjectName());
        //查詢屬性
        Assert.assertEquals(mBeanInfo.getClassName(), ShardInfo.class.getName());
        Assert.assertEquals("sunquan", server.getAttribute(shardInfo.getMBeanObjectName(), "ShardName"));
        //執行方法
        server.invoke(shardInfo.getMBeanObjectName(), "printShardName", null, null);
    }

如何避免每個靜態MBean都要單獨定義接口

目前考慮有下列兩個方法:

  1. 開發MBean上的相關注解,觸發在編譯期其注入方法至接口類中
  2. 使用動態MBean實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章