プラットホームMBeanサーバと独自MXBean
Java6より、インタフェースとアノテーションによってMXBeanは非常に簡単に作れるようになった。
例えば私が実際に作っている「コードベース及びソケットのリスンポートを返すMXBean」は、以下のようにインタフェースにMXBeanアノテーションを付加することで定義される。
@MXBean
public interface ICodeBaseAgent {
String getCodeBase();
int getListenPort();
}
実際にこのMXBeanを公開するには、このインタフェースを実装するJavabeansクラスを用意して、MBeanサーバに登録するだけでよい。(実際にはRMIローカルレジストリが起動されている必要があるが、割愛)
//MBeanサーバの起動又は取得 //server = MBeanServerFactory.createMBeanServer(); server = ManagementFactory.getPlatformMBeanServer(); //MXBeanをプラットホームMBeanサーバに登録 ObjectName name = new ObjectName("com.kazz.impl:type=ICodeBaseAgent"); CodeBaseAgentImpl agent = new CodeBaseAgentImpl(); server.registerMBean(agent, name);
MXBeanを公開するMBeanサーバは、元々JSDKが用意している「プラットホームMBeanサーバ」か独自に作成するMBeanサーバを選ぶ必要があるが、JConsoleからの接続を受け入れることや、特に設定が必要無い簡便さからプラットホームMBeanサーバを選ぶことが多いだろう。(上記サンプルもプラットホームMBeanサーバを取得している)
さて、プラットホームMBeanサーバに登録/公開されたMXBeanを他のアプリケーションから取得するには、前回のエントリで説明したように、ローカルコネクタアドレスを取得した上でMXBeanへの接続を確立するJMXConnectorオブジェクトを生成する必要がある。
//プラットホームMBeanサーバローカルコネクタアドレスに接続するためのコネクタを取得する JMXServiceURL url = new JMXServiceURL(connectorAddress); JMXConnector connector = JMXConnectorFactory.connect(url);
コネクタが無事取得できれば、あとはコネクタを介してMBeanサーバから該当のオブジェクト名(ObjectName)を持つMXBeanのプロキシを取得すれば良い。
MBeanServerConnection connection = connector.getMBeanServerConnection(); //RMIを介しているため、取得するのはMXBeanのプロキシ(動的プロキシ)となる ICodeBaseAgent agent = ManagementFactory.newPlatformMXBeanProxy(connection, "com.kazz.impl:type=ICodeBaseAgent", ICodeBaseAgent.class);
さあこれでOKかと思いきや、実行すると「このMXBeanはプラットホームMBeanではない」と怒られてしまう。
Exception in thread "main" java.lang.IllegalArgumentException: com.kazz.impl:type=ICodeBaseAgent is not a platform MXBean
この場合、以下のようにMBeanServerInvocationHandlerを使わなくてはならないのだ。
ObjectName on = new ObjectName("com.kazz.impl:type=ICodeBaseAgent"); ICodeBaseAgent agent = MBeanServerInvocationHandler.newProxyInstance(connection, on, ICodeBaseAgent.class, false);
正直、同じMBeanサーバ上に登録されているMXBeanをnewPlatformMXBeanProxyメソッドで取得できないのは納得がいかないのだが、こうしないと動かないので仕方が無い。
なお、上記では取得したMXBeanをインタフェースに直接キャストしているが、実際にはMBeanServerConnection#isInstanceOfメソッドを使って、現在接続しているMXBeanの型を前もってチェックすることで、InstanceNotFoundExceptionを捕捉できるようになる。
ObjectName on = new ObjectName("com.kazz.impl:type=ICodeBaseAgent"); MBeanServerConnection connection = connector.getMBeanServerConnection(); if (connection.isInstanceOf(on, "com.kazz.ICodeBaseAgent ")) { ICodeBaseAgent agent = MBeanServerInvocationHandler.newProxyInstance(connection, on, ICodeBaseAgent.class, false); }
これでようやく、他のアプリケーションが公開している情報を読み取れるようになった訳だ。