jolokiaでMBeanアクセス

# 経緯

MBean経由で情報取得したくなったのだけれど、
クライアント作るのも面倒で何かいいのないかと探していて、
Jolokiaなるものを、いまさら覚えた。

Jolokiaを使うと、HTTP経由でアクセスが可能になるので、
curl使ったり、ブラウザでちらっと見たり、とても楽。

でも、Heap情報取得するものなど、デフォルトのものばかり情報多くて、
自前で作成したMBeanの取得方法がなかなか見つからず、自作してみました。

# 検証

## 起動パラメータ
* いろんなところに書いてあるけど、Javaの起動パラメータに以下を追加。

```bash
-javaagent:./lib/jolokia-jvm-1.3.7-agent.jar=port=8778,host=localhost
```
* Jolokiaは [Jolokia公式サイト](https://jolokia.org/download.html) から取得
  * JVM-Agentをダウンロードすれば使用可能。

## Mean
* 次のようなMBeanを作成したとする。
* 全ソースは [Github参照](https://github.com/nobutnk/spring-integration-hello)

```java
package com.nobutnk.springintegration.example.service.cafe;

import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;

@ManagedResource
public class ThreadPoolMBean {

    private ThreadPoolExecutor executorService;
    
    public ThreadPoolMBean(ThreadPoolExecutor service) {
        executorService = service;
    }

    @ManagedAttribute(description = "Returns the number of threads that execute tasks")
    public int getActiveCount() {
        return executorService.getActiveCount();
    }

    @ManagedAttribute(description = "Returns the total number of completed tasks")
    public long getCompletedTaskCount() {
        return executorService.getCompletedTaskCount();
    }

    @ManagedAttribute(description = "Returns the size of the core pool of threads")
    public int getCorePoolSize() {
        return executorService.getCorePoolSize();
    }

    @ManagedAttribute(description = "Returns the largest number of threads that have been in the pool")
    public int getLargestPoolSize() {
        return executorService.getLargestPoolSize();
    }

    @ManagedAttribute(description = "Returns the max size allowed in the pool of threads")
    public int getMaximumPoolSize() {
        return executorService.getMaximumPoolSize();
    }

    @ManagedAttribute(description = "Returns the number of additional elements that this queue can "
            + "accept without  "
            + "blocking")
    public int getQueueRemainingCapacity() {
        return executorService.getQueue().remainingCapacity();
    }
    
    @ManagedAttribute(description = "Returns the queue size ")
    public int getQueueSize() {
        return executorService.getQueue().size();
    }

    @ManagedAttribute(description = "Returns the total number of tasks that have ever been scheduled for execution ")
    public long getTaskCount() {
        return executorService.getTaskCount();
    }

    @ManagedAttribute(description = "Sets the core size of the pool")
    public void setCorePoolSize(int corePoolSize) {
        executorService.setCorePoolSize(corePoolSize);
    }

    @ManagedAttribute(description = "Sets the max size allowed in the pool of threads")
    public void setMaximumPoolSize(int maximumPoolSize) {
        executorService.setMaximumPoolSize(maximumPoolSize);
    }
}
```

* 以下のような設定を使用。全ソースは[applicationContext-queue.xml](https://github.com/nobutnk/spring-integration-hello/blob/master/src/main/resources/META-INF/spring/applicationContext-queue.xml)

```xml
    <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
        <property name="autodetect" value="true" />
        <property name="namingStrategy" ref="namingStrategy" />
        <property name="assembler" ref="assembler" />
    </bean>
     
    <bean id="jmxAttributeSource" class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource" />
     
    <bean id="assembler" class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
        <property name="attributeSource" ref="jmxAttributeSource" />
    </bean>
     
    <bean id="namingStrategy" class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
        <property name="attributeSource" ref="jmxAttributeSource" />
    </bean>
    
    <bean id="threadPoolMBean" class="com.nobutnk.springintegration.example.service.cafe.ThreadPoolMBean" >
        <constructor-arg type="java.util.concurrent.ThreadPoolExecutor" ref="executorService"/>
    </bean>
        <property name="corePoolSize" value="2" />
        <property name="maxPoolSize" value="2" />
        <property name="queueCapacity" value="1000" />
    </bean>
```

* あとは起動すれば、MBeanにアクセス可能になる。
  * Main関数は [AddQueue#main](https://github.com/nobutnk/spring-integration-hello/blob/master/src/main/java/com/nobutnk/springintegration/example/mian/AppQueue.java)

## Jolokiaでの取得
* Heap情報
  * `http://localhost:8778/jolokia/read/java.lang:type=Memory` とブラウザでアクセスすると、以下が取得できる。（見やすく整形してます）

  ```json
  {
  "request":
  {
    "mbean":"java.lang:type=Memory",
    "type":"read"
  },
  "value":
  {
    "ObjectPendingFinalizationCount":0,
    "Verbose":false,
    "HeapMemoryUsage":
    {
      "init":67108864,
      "committed":81264640,
      "max":954728448,
      "used":15444856
    },
    "NonHeapMemoryUsage":
    {
      "init":2555904,
      "committed":26869760,
      "max":-1,
      "used":26229496
    },
    "ObjectName":
    {
      "objectName":"java.lang:type=Memory"
    }
  },
  "timestamp":1516721831,
  "status":200
}
  ```
  * `http://localhost:8778/jolokia/read/java.lang:type=Memory/HeapMemoryUsage` まで書けば、もっと絞って。（見やすく整形してます）
  
  ```json
  {
  "request":
  {
    "mbean":"java.lang:type=Memory",
    "attribute":"HeapMemoryUsage",
    "type":"read"
  },
  "value":
  {
    "init":67108864,
    "committed":81264640,
    "max":954728448,
    "used":16991088
  },
  "timestamp":1516721940,
  "status":200
  }
  ```

## 本題
* 自分で作成した `ThreadPoolMBean` の情報を取得するにはどうアクセスすればいいか。
* `http://localhost:8778/jolokia/read/com.nobutnk.springintegration.example.service.cafe:name=threadPoolMBean,type=ThreadPoolMBean/TaskCount`
  * `/read/` : 情報取得
  * `com.nobutnk.springintegration.example.service.cafe` : パッケージ
  * `:name= threadPoolMBean` : beanの名前. 上記で書いたbean@id。クラス名ではない。
  * `,type= ThreadPoolMBean` : クラス名
  * `/TaskCount` : getTaskCountのこと
* レスポンス（見やすく整形してます）

```json
{"request":
  {
    "mbean":"com.nobutnk.springintegration.example.service.cafe:name=threadPoolMBeanTest,type=ThreadPoolMBean",
    "attribute":"TaskCount",
    "type":"read"
  },
  "value":23,
  "timestamp":1516722234,
  "status":200
  }
```

* どんな情報取得できるかわからなかったら、クラス名までで取得する。
  * `http://localhost:8778/jolokia/read/com.nobutnk.springintegration.example.service.cafe:name=threadPoolMBean,type=ThreadPoolMBean/`
  * レスポンス（見やすく整形してます）
  
  ```json
  {"request":
    {
  "mbean":"com.nobutnk.springintegration.example.service.cafe:name=threadPoolMBeanTest,type=ThreadPoolMBean","type":"read"},
  "value":
    {"QueueSize":0,"MaximumPoolSize":2,
     "CompletedTaskCount":4,
     "LargestPoolSize":2,
     "TaskCount":4,
     "ActiveCount":0,
     "CorePoolSize":2,
     "QueueRemainingCapacity":1000},
  "timestamp":1516722434,
  "status":200}
  ```

# 最後に
* ログに情報出しておくのもいいけど、こうやってリアルタイムに取得できるのも使いどころあるかなと考えさせられました。