11 JMXコネクタ
この章では、標準および動的な管理Bean (MBean)の概念を紹介します。JMXテクノロジを使用してMBean上でローカルおよびリモートから操作を実行する方法について示します。
RMIコネクタを使用した標準および動的MBeanへのアクセス
この例では、標準および動的MBeanを説明します。
JMX APIの基本要素で説明したように、標準MBeanは内部のメソッドの名前を使用して管理インタフェースを静的に定義します。動的MBeanは、特定のJavaインタフェースを実装し、実行時に自らの属性と操作を示します。
JMXテクノロジは、Remote Method Invocation (RMI)を基にしたコネクタを定義します。RMIコネクタは、Java Remote Method Protocol (JRMP)トランスポートをサポートします。このコネクタを使用すると、MBeanサーバーのMBeanにリモート接続し、ローカルで操作を実行するのとまったく同じように、そのMBeanで操作を実行できます。
この例は、標準MBeanと動的MBeanの実装を説明することを目的としています。両方でローカルに、またサーバーとリモート・クライアント間のRMI接続を通じてリモートに操作を実行する方法も示します。
この例を実行する場合
-
サーバー側:
-
MBeanサーバーを作成
-
ローカルMBeanサーバーに
SimpleStandard
とSimpleDynamic
のMBeanを登録 -
両MBean上でローカル操作を実行
-
RMIコネクタ・サーバーを作成
-
-
クライアント側:
-
RMIコネクタを作成
-
リモートMBeanサーバーに
SimpleStandard
とSimpleDynamic
のMBeanを登録 -
両MBeanでリモート操作を実行
-
基本MBeanの例で使用したクラスの分析
-
「JMXコネクタ」の項に含まれているソース・コードをコピーし、対応するファイルを
work_dir/jmx_examples/Basic
ディレクトリに作成します。このディレクトリ内のファイルには、次の情報が含まれます。Server.java
SimpleStandardMBean.java
SimpleStandard.java
SimpleDynamic.java
ClientListener.java
Client.java
README
-
各
*.java
ファイルをIDEまたはテキスト・エディタで開きます。
次のセクションでは、基本的なMBeanの例題で使用される各クラスを分析し、それらのクラスがこれまでのセクションで説明した操作をどのように実行するかについて説明します。
MBeanの例題のServer.java
Server.java
クラスは、その大きさにより、次の一連のコード(抜粋)で分析されます。
コード例11-1 MBeanの例クラスServer.java (抜粋1)
public class Server {
public static void main(String[] args) {
try {
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
waitForEnterPressed();
String domain = mbs.getDefaultDomain();
waitForEnterPressed();
String mbeanClassName = "SimpleStandard";
String mbeanObjectNameStr =
domain + ":type=" + mbeanClassName + ",name=1";
ObjectName mbeanObjectName =
createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr);
waitForEnterPressed();
printMBeanInfo(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();
manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();
mbeanClassName = "SimpleDynamic";
mbeanObjectNameStr =
domain + ":type=" + mbeanClassName + ",name=1";
mbeanObjectName =
createSimpleMBean(mbs, mbeanClassName, mbeanObjectNameStr);
waitForEnterPressed();
printMBeanInfo(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();
manageSimpleMBean(mbs, mbeanObjectName, mbeanClassName);
waitForEnterPressed();
[...]
このクラスを検討すると、次のイベントが起こっていることがわかります。
まず、Server.java
クラスは、MBeanServerFactory
クラスのcreateMBeanServer()
メソッドを呼び出してmbs
と呼ばれる新しいMBeanサーバーを作成します。
次にMBeanサーバーを登録するデフォルト・ドメインを、MBeanServer
インタフェースのgetDefaultDomain()
メソッドを呼び出して取得します。このドメインは、文字列domain
で識別されます。
MBeanクラスSimpleStandard
も、この場合は文字列mbeanClassName
という変数により識別されます。SimpleStandard
は、このMBeanをインスタンスとするJavaオブジェクトのJavaクラスの名前です。
もう1つの変数、文字列mbeanObjectNameStr
は、ドメインと次のキー=値ペアを組み合わせて定義されます。
type
。この場合は、mbeanClassName
。name
。このMBeanを、後で作成される同じタイプの他のMBeanと区別します。この場合、name番号は1
です。
mbeanObjectNameStr
の目的は、人間が読むことができる識別子をMBeanに割り当てることです。
createSimpleMBean()の呼出しにより、指定されたオブジェクト名のSimpleStandard MBeanがローカルMBeanサーバーで作成され、登録されます。
次に、printMBeanInfo()
とmanageSimpleMBean()
の両方の操作が、SimpleStandard
MBeanで実行されます。createSimpleMBean()
と同様、これらのメソッドは後でServer.java
コードで定義され、コード例11-4 MBeanの例題クラスServer.java (抜粋4)とコード例11-5 MBeanの例題クラスServer.java (抜粋5)で示されます。
このコードには記述されていませんが、SimpleDynamic
型の2番目のMBeanが、SimpleStandard
MBeanとまったく同じ方法でMBeanサーバーに作成され、登録されます。名前が示すように、このMBeanはMBeanの例のSimpleDynamic.javaで説明するSimpleDynamic
Javaオブジェクトのインスタンスです。
コード例11-2 MBeanの例クラスServer.java (抜粋2)
[...]
JMXServiceURL url =
new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnectorServer cs =
JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);
cs.start();
waitForEnterPressed();
cs.stop();
[...]
コード例11-2 MBeanの例題クラスServer.java (抜粋2)では、RMIコネクタ・サーバーはMBeanでリモート操作ができるように作成されています。JMXServiceURL
クラスを呼び出すと、コネクタ・サーバーのアドレスとなるurl
という新しいサービスURLが作成されます。この例では、サービスURLはエンコード形式ではなくJNDI形式で指定されます(JNDI形式の詳細は、javax.management.remote.rmi
パッケージのAPIドキュメントを参照)。このサービスURLは、次の内容を定義しています。
- コネクタは
rmi
で表されるデフォルトのRMIトランスポートを使用する。 - RMIコネクタ・スタブが保存されるRMIレジストリは、ローカル・ホストのポート
9999
で稼働し、サーバー・アドレスはserver
の名前で登録される。例で指定されるポート9999
は任意の数字。使用可能なポートを指定できる。
RMIコネクタ・サーバーcs
は、パラメータにサービスURL url
、null
環境マップ、およびMBeanサーバーmbs
を使用して、コンストラクタJMXConnectorServerFactory
を呼び出して作成されます。コネクタ・サーバーcs
は、JMXConnectorServer
のstart()
メソッドを呼び出し、RMIConnectorServer
がRMIオブジェクトserver
をRMIレジストリにエクスポートすることで起動されます。この接続は、Enterキーを押すまで有効です。これはServer
コードの後半で定義する簡単なメソッドwaitForEnterPressed
の手順に従ったものです。
コード例11-3 MBeanの例クラスServer.java (抜粋3)
[...]
private static ObjectName createSimpleMBean(MBeanServer mbs,
String mbeanClassName,
String mbeanObjectNameStr) {
echo("\n>>> Create the " + mbeanClassName +
" MBean within the MBeanServer");
echo("ObjectName = " + mbeanObjectNameStr);
try {
ObjectName mbeanObjectName =
ObjectName.getInstance(mbeanObjectNameStr);
mbs.createMBean(mbeanClassName, mbeanObjectName);
return mbeanObjectName;
} catch (Exception e) {
echo( "!!! Could not create the " +
mbeanClassName + " MBean !!!");
e.printStackTrace();
echo("\nEXITING...\n");
System.exit(1);
}
return null;
}
[...]
コード例11-3 MBeanの例題クラスServer.java (抜粋3)は、createSimpleMBean()
メソッドの定義を示しています。このメソッドでは、オブジェクト名mbeanObjectNameStr
がObjectName
インタフェースのgetInstance()
メソッドに渡され、MBeanサーバー内でMBeanの登録に使用される新しいオブジェクト名が作成されます。最終的なオブジェクト名インスタンスは、mbeanObjectName
に設定されます。MBeanServer
メソッドcreateMBean()
を呼び出すと、mbeanClassName
とmbeanObjectName
のインスタンスの組合せで定義されたMBeanがインスタンス化されてから、MBeanサーバーmbs
にMBeanが登録されます。
コード例11-4 MBeanの例クラスServer.java (抜粋4)
[...]
private static void printMBeanInfo(MBeanServer mbs,
ObjectName mbeanObjectName,
String mbeanClassName) {
MBeanInfo info = null;
try {
info = mbs.getMBeanInfo(mbeanObjectName);
} catch (Exception e) {
echo( "!!! Could not get MBeanInfo object for " +
mbeanClassName +" !!!");
e.printStackTrace();
return;
}
MBeanAttributeInfo[] attrInfo = info.getAttributes();
if (attrInfo.length > 0) {
for (int i = 0; i < attrInfo.length; i++) {
echo(" ** NAME: " + attrInfo[i].getName());
echo(" DESCR: " + attrInfo[i].getDescription());
echo(" TYPE: " + attrInfo[i].getType() +
"READ: "+ attrInfo[i].isReadable() +
"WRITE: "+ attrInfo[i].isWritable());
}
} else echo(" ** No attributes **");
[...]
コード例11-4 MBeanの例クラスServer.java (抜粋4)に、メソッドprintMBeanInfo()
の定義が示されています。printMBeanInfo()
メソッドはMBeanServer
のメソッドgetMBeanInfo()
を呼び出して、mbeanObjectName
で指定されたMBeanにより開示される属性と操作の詳細を取得します。MBeanAttributeInfo
は次のメソッドを定義します。それらのメソッドはそれぞれ、MBeanの属性に関する情報を取得するために呼び出されます:
getName
: 属性の名前を取得する。getDescription
: 人間が読むことのできる属性の説明を取得する。getType
: 属性のクラス名を取得する。isReadable
: 属性が読出し可能かどうかを判断する。isWritable
: 属性が書込み可能かどうかを判断する。
ここには示していませんが、呼出しが行われるのは、MBeanのコンストラクタ、操作、および通知に関する情報を取得するためです:
MBeanConstructorInfo
: MBeanのJavaクラスに関する情報を取得する。MBeanOperationInfo
: MBeanで実行される操作の内容、およびMBeanで使用されるパラメータの種類を学習する。MBeanNotificationInfo
: MBeanの操作が実行された場合に、MBeanから送信される通知の種類を調べる。
コード例11-5 MBeanの例クラスServer.java (抜粋5)
[...]
private static void manageSimpleMBean(MBeanServer mbs,
ObjectName mbeanObjectName,
String mbeanClassName) {
try {
printSimpleAttributes(mbs, mbeanObjectName);
Attribute stateAttribute = new Attribute("State",
"new state");
mbs.setAttribute(mbeanObjectName, stateAttribute);
printSimpleAttributes(mbs, mbeanObjectName);
echo("\n Invoking reset operation...");
mbs.invoke(mbeanObjectName, "reset", null, null);
printSimpleAttributes(mbs, mbeanObjectName);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void printSimpleAttributes(
MBeanServer mbs,
ObjectName mbeanObjectName) {
try {
String State =
(String) mbs.getAttribute(mbeanObjectName, "State");
Integer NbChanges =
(Integer) mbs.getAttribute(mbeanObjectName,
"NbChanges");
} catch (Exception e) {
echo( "!!! Could not read attributes !!!");
e.printStackTrace();
}
}
[...]
コード例11-5 MBeanの例題クラスServer.java (抜粋5)は、簡単なMBeanを管理するためのメソッドを示しています。
まず、manageSimpleMBean()
メソッドが、Server
でも定義されるprintSimpleAttributes()
メソッドを呼び出します。printSimpleAttributes()
メソッドは、MBean mbeanObjectName
からstate
というMBean属性と、NbChanges
というもう1つのMBean属性を取得します。
次にmanageSimpleMBean()
メソッドは、Attribute
クラスのインスタンスである属性stateAttribute
を定義します。stateAttribute
属性は、値new state
をSimpleStandard
で定義される既存の属性state
に関連付けます。次にMBeanServer
のsetAttribute()
メソッドに呼び出すことで、mbeanObjectName
MBeanの状態がstateAttribute
で定義される新しい状態に設定されます。
最後にMBeanServer
のinvoke()
メソッドに呼び出すことで、mbeanObjectName
MBeanのreset
操作が起動します。reset
操作は、SimpleStandard
クラスで定義されます。
MBeanの例題のSimpleStandardMBean.java
次のコード例に、SimpleStandardMBean.java
クラスを示します。
コード例11-6 MBeanの例題クラスSimpleStandardMBean.java
public interface SimpleStandardMBean {
public String getState();
public void setState(String s);
public int getNbChanges();
public void reset();
}
SimpleStandardMBean.java
クラスは、MBean SimpleStandard
の簡単なJMX仕様の管理インタフェースです。このインタフェースは、JMXエージェントからの管理のためにSimpleStandard
で定義された4つの操作を公開します。
MBeanの例題のSimpleStandard.java
次のコード例に、SimpleStandard.java
クラスを示します。
コード例11-7 MBeanの例題クラスSimpleStandard.java
public class SimpleStandard
extends NotificationBroadcasterSupport
implements SimpleStandardMBean {
public String getState() {
return state;
}
public void setState(String s) {
state = s;
nbChanges++;
}
public int getNbChanges() {
return nbChanges;
}
public void reset() {
AttributeChangeNotification acn =
new AttributeChangeNotification(this,
0,
0,
"NbChanges reset",
"NbChanges",
"Integer",
new Integer(nbChanges),
new Integer(0));
state = "initial state";
nbChanges = 0;
nbResets++;
sendNotification(acn);
}
public int getNbResets() {
return nbResets;
}
public MBeanNotificationInfo[] getNotificationInfo() {
return new MBeanNotificationInfo[] {
new MBeanNotificationInfo(
new String[] {
AttributeChangeNotification.ATTRIBUTE_CHANGE },
AttributeChangeNotification.class.getName(),
"This notification is emitted when the reset()
method is called.")
};
}
private String state = "initial state";
private int nbChanges = 0;
private int nbResets = 0;
}
SimpleStandard
クラスは、簡単なJMX仕様の標準MBeanを定義します。SimpleStandard
MBeanは、対応するSimpleStandardMBean
インタフェースを実装することで、管理のための操作と属性を公開します。
このMBeanで開示される簡単な操作を次に示します。
-
状態を定義する
-
この状態を更新する
-
状態の更新回数をカウントする
-
状態の値と、変更回数を元の値であるゼロにリセットする
-
リセット操作が呼び出された場合に常に通知を送信する
リセット操作により発行される通知は、クラスAttributeChangeNotification
のインスタンスであり、リセットの呼出し前にState
属性で実行された変更数に関する情報を収集します。送信される通知の内容は、MBeanNotificationInfo
インスタンスで定義されます。
MBeanの例題のSimpleDynamic.java
次のコード例に、SimpleDynamic
クラスを示します。
コード例11-8 MBeanの例題クラスSimpleDynamic.java
public class SimpleDynamic
extends NotificationBroadcasterSupport
implements DynamicMBean {
public SimpleDynamic() {
buildDynamicMBeanInfo();
}
[...]
SimpleDynamic
の動的MBeanでは、DynamicMBean
インタフェースを実装することで、実行時に管理用の属性と操作を開示する方法を示します。ここでは、まず、MBeanに関する情報を動的に取得するためのメソッドbuildDynamicMBeanInfo()
の定義から開始します。buildDynamicMBeanInfo()
メソッドは、動的MBeanにMBeanInfo
を構築します。
SimpleDynamic
のほかのコードは、DynamicMBean
インタフェースの実装に対応しています。開示される属性、操作、通知は、SimpleStandard
MBeanで開示されるものと同じです。
MBeanの例題のClientListener.java
次のコード例に、ClientListener.java
クラスを示します。
コード例11-9 MBean例題クラスClientListener.java
public class ClientListener implements NotificationListener {
public void handleNotification(Notification notification, Object handback)
{
System.out.println("\nReceived notification: " + notification);
}
}
ClientListener
クラスは、簡単なJMX仕様の通知リスナーを実装します。通知が受領されると、NotificationListener
インタフェースのhandleNotification()
メソッドが呼び出され、通知の受領を確認するためのメッセージが出力されます。
MBeanの例題のClient.java
次のコード例に、Client.java
クラスを示します。
コード例11-10 MBean例題クラスClient.java
public class Client {
public static void main(String[] args) {
try {
// Create an RMI connector client
//
JMXServiceURL url = new JMXServiceURL(
"service:jmx:rmi:///jndi/rmi://localhost:9999/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
ClientListener listener = new ClientListener();
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
waitForEnterPressed();
// Get domains from MBeanServer
//
String domains[] = mbsc.getDomains();
for (int i = 0; i < domains.length; i++) {
System.out.println("Domain[" + i + "] = " + domains[i]);
}
waitForEnterPressed();
String domain = mbsc.getDefaultDomain();
// Create SimpleStandard MBean
ObjectName mbeanName =
new ObjectName(domain +":type=SimpleStandard,name=2");
mbsc.createMBean("SimpleStandard", stdMBeanName, null, null);
waitForEnterPressed();
// Create SimpleDynamic MBean
ObjectName dynMBeanName =
new ObjectName(domain +":type=SimpleDynamic,name=2");
echo("\nCreate SimpleDynamic MBean...");
mbsc.createMBean("SimpleDynamic", dynMBeanName, null, null);
waitForEnterPressed();
// Get MBean count
echo("\nMBean count = " + mbsc.getMBeanCount());
// Query MBean names
echo("\nQuery MBeanServer MBeans:");
Set names = mbsc.queryNames(null, null);
for (Iterator i = names.iterator(); i.hasNext(); ) {
echo( "ObjectName = " + (ObjectName) i.next());
}
waitForEnterPressed();
mbsc.setAttribute(stdMBeanName,
new Attribute("State", "changed state"));
SimpleStandardMBean proxy = JMX.newMBeanProxy(
mbsc, stdMBeanName, SimpleStandardMBean.class, true);
echo("\nState = " + proxy.getState());
ClientListener listener = new ClientListener();
mbsc.addNotificationListener(stdMBeanName, listener, null, null);
mbsc.invoke(stdMBeanName, "reset", null, null);
mbsc.removeNotificationListener(stdMBeanName, listener);
mbsc.unregisterMBean(stdMBeanName);
[...]
jmxc.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
[...]
Client.java
クラスは、RMIコネクタ・クライアントを作成します。このクライアントは、Server.java
で作成されるRMIコネクタ・サーバーへの接続用に構成されます。Client.java
は、Server.java
.で定義されるのと同じサービスURL url
を定義します。これによって、コネクタ・クライアントは、ローカル・ホストのポート9999
で動作するRMIレジストリからRMIコネクタ・サーバー・スタブserver
を取得し、RMIコネクタ・サーバーに接続することができます。
RMIレジストリが特定された場合、コネクタ・クライアントを作成できます。コネクタ・クライアントjmxc
は、JMXConnectorFactory
のconnect()
メソッドにより作成されたインタフェースJMXConnector
のインスタンスです。connect()
メソッドは、呼び出されると、パラメータurl
とnull
環境マップが渡されます。
またクライアントは、MBeanの例題のClientListener.javaに示すように、ClientListener
のインスタンスを作成して通知を待機します。
次に、JMXConnector
インスタンスjmxc
のgetMBeanServerConnection()
メソッドを呼び出して、JMX仕様MBeanServerConnection
のインスタンスmbsc
が作成されます。
これによってコネクタ・クライアントはServer.java
で作成されたMBeanサーバーに接続され、両端への接続が完全に透過的な状態にあればMBeanの登録とMBeanでの操作が可能になります。
クライアントは、MBeanServerConnection
のcreateMBean()
メソッドを呼び出して、MBeanサーバーにSimpleStandard
MBeanとSimpleDynamic
MBeanを作成および登録します。そして、SimpleStandard
とSimpleDynamic
で定義された操作を、ローカルJMX仕様のMBean操作とまったく同様に実行します。
MBeanプロキシによりJavaインタフェースを介してMBeanにアクセスできるため、長いコードを記述しなくても、プロキシ上で呼び出してリモートMBeanにアクセスできます。SimpleStandardMBean
のMBeanプロキシをここで作成するには、javax.management.JMX
クラスのnewMBeanProxy()
メソッドを呼び出し、MBeanのMBeanServerConnection
オブジェクト、MBeanインタフェースのクラス名、およびtrueを渡して、このプロキシがNotificationBroadcaster
として動作する必要があることを知らせます。MXBeanのプロキシを標準MBeanの場合とまったく同じ方法で作成するには、newMBeanProxy()
ではなくnewMXBeanProxy()
を呼び出します。
SimpleDynamic
で実行される各操作は、SimpleStandard
で実行されるものと同じであるため、ここでは操作のコードを記載していません。
最後に、クライアントはSimpleStandard
MBeanの登録を解除し、接続を終了します。最後のremoveNotificationListener
はオプションです。これはリモート・クライアントで登録されたリスナーは、そのクライアントの終了時に削除されるためです。
MBeanの例題の実行
例題のクラスを検証した後、例題を実行できます。例題を実行するには:
- Javaクラスをコンパイルします。
$ javac *.java
- ローカル・ホストのポート
9999
でRMIレジストリを起動します。RMIレジストリは、
Server
クラスによってRMIコネクタ・スタブの登録に使用されます。$ rmiregistry 9999 &
Server
クラスを起動します。$ java -classpath . Server
MBeanサーバーの作成、およびMBeanサーバーでの
SimpleStandard
MBeanの作成を確認するプロンプトが表示されます。次にSimpleStandard
MBeanに関する情報を取得し、このMBeanで操作を実行する場合は、Enterキーを押すように要求されます。SimpleStandard
での操作が終了した後、SimpleDynamic
MBeanについて、同じプロセスが繰り返されます。両方のMBeanが作成されてその操作が実行された後、RMIコネクタ・サーバーが作成され、リモートの
Client
からMBeanでの操作が可能になります。- 別の端末ウィンドウで
Client
クラスを起動します。$ java -classpath . Client
RMIコネクタの作成、およびコネクタ・サーバーとの接続の作成の確認が表示されます。ドメイン名と、
SimpleStandard
およびSimpleDynamicのMBeanの作成と登録についても通知されます。クライアントは、SimpleStandard
とSimpleDynamicの両MBeanで操作を実行し、その後、両MBeanの登録を解除します。