Fenriswolf 程式筆記

奮利斯狼的地盤,小綿羊勿入

JMX – 自訂 mbeans

在複雜的系統裡需要監控的資源不是只有 log, datasources, schedule jobs 那麼簡單
還會有自訂的一些資源
JMX 提供了 Standard MBean 和 Dynamic MBean 兩種實作方式
不過這篇文章會以 spring 來定義及控管自訂的 mbeans

1. export services to mbeans
假設在系統中已經有一個 ResourceBundleService 來存取 env.properties,程式如下
ResourceBundleService.java

public interface ResourceBundleService {
    public String getString(String key);

    public String getBaseName();
}

ResourceBundleServiceImpl.java

public class ResourceBundleServiceImpl implements ResourceBundleService,
        InitializingBean {
    private String baseName;
    private ResourceBundle resourceBundle;

    public String getString(String key){
        return resourceBundle.getString(key);
    }
    
    public void afterPropertiesSet() throws Exception {
        resourceBundle = ResourceBundle.getBundle(baseName);
    }

    public String getBaseName() {
        return baseName;
    }

    public void setBaseName(String baseName) throws Exception {
        this.baseName = baseName;
        afterPropertiesSet();
    }
}

在 spring 的定義

<bean id="resourceBundleService"
    class="com.fw.jmx.ResourceBundleServiceImpl">
    <property name="baseName" value="env" />
</bean>

註冊成 mbean 的方法非常簡單,只要在 MBeanExporter 裡直接設定就好了

<bean id="exporter"
    class="org.springframework.jmx.export.MBeanExporter">
    <property name="beans">
        <map>
            <entry key="server:name=resourceBundleService"
                value-ref="resourceBundleService" />
        </map>
    </property>
    <property name="server" ref="mbeanServer" />
</bean>

接下來就是看執行結果

既然這麼容易,為什麼 log4j、c3p0 datasource、quartz schedule job 不用這種方式設定???
原因有三個

  1. 最重要的一點,call setBaseName method 並不會更新 ResourceBundle。一般來說,執行時期不會去更改系統參數,所以要特別注意
  2. spring 用 reflection 的方式抓出 ResourceBundleServiceImpl 所有的 methods,包括不需要用到的 methods 如 afterPropertiesSet()
  3. 畫面顯示的資訊並不完整,如 methods 沒有說明,參數以 p1、p2 顯示

第一個問題要改 setBaseName method,加入 reload propertiles file 的動作

public void setBaseName(String baseName) throws Exception {
    this.baseName = baseName;
    afterPropertiesSet();
}

其他的問題可由設定 Assembler 解決

2. 定義 Assembler
spring 定義了好幾種 assemblers 可供設定
a. SimpleReflectiveMBeanInfoAssembler
這是 spring 預設的 assembler,結果如上面顯示就不多做介紹

b. InterfaceBasedMBeanInfoAssembler
可過濾不需要的 methods
先定義一個新的 interface,少了 afterPropertiesSet method

public interface ResourceBundleServiceMBean {
    public String getString(String key);

    public String getBaseName();

    public void setBaseName(String baseName);
}

這裡不延用 ResourceBundleService interface
因為 setBaseName method 應該要由 administrator 來設定
而不是由 developer 透過程式控制

在 spring 中 assembler 的定義

<bean id="assembler"
  class="org.springframework.jmx.export.assembler.InterfaceBasedMBeanInfoAssembler">
    <property name="interfaceMappings">
        <props>
            <prop key="resourceBundleService">
                com.fw.jmx.ResourceBundleServiceMBean
            </prop>
        </props>
    </property>
</bean>

在 MBeanServerFactoryBean 加入 assembler 的參數

<property name="assembler" ref="assembler" />

c. MetadataMBeanInfoAssembler
用 annotation 的方式定義,可設定最完整的資訊
annotation 的用法蠻直覺的就不多做解釋

@ManagedResource(description = "ResourceBundleService MBean")
public class ResourceBundleServiceImpl implements ResourceBundleService,
        InitializingBean {
    private String baseName;
    private ResourceBundle resourceBundle;

    @ManagedOperation(description="Gets a string for the given key")
    @ManagedOperationParameters({
      @ManagedOperationParameter(name = "key", 
                                 description = "the key for the desired string")})
    public String getString(String key) {
        return resourceBundle.getString(key);
    }

    public void afterPropertiesSet() throws Exception {
        resourceBundle = ResourceBundle.getBundle(baseName);
    }

    @ManagedAttribute(defaultValue="env")
    public String getBaseName() {
        return baseName;
    }

    @ManagedAttribute(description="the base name of the resource bundle")
    public void setBaseName(String baseName) throws Exception {
        this.baseName = baseName;
        afterPropertiesSet();
    }
}

接下來是 spring 的定義

<bean id="attributeSource"
  class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
    
<bean id="assembler"
    class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
    <property name="attributeSource" ref="attributeSource" />
</bean>

 
 
1.5 jconsole 的結果,滑鼠移上去就會顯示 tooltip

這是 1.6 jconsole 的結果,所有資訊比較一目了然

 
 
執行環境
JDK 1.5.0_11(因為 1.6 的 jconsole 太醜了)
spring 2.5
log4j 1.2.14
c3p0 0.9.1.2
quartz 1.6
mx4j 3.0.2

參考資料
JMX Tutorial
Spring JMX
log4j 1.2
c3p0
Quartz JMX Management
MX4J
Java Dynamic Management Kit

程式下載
ResourceBundleService.java
ResourceBundleServiceImpl.java
ResourceBundleServiceMBean.java
appContext.xml

廣告

2012/03/20 - Posted by | Java SE | ,

仍無迴響。

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

w

連結到 %s

%d 位部落客按了讚: