JBoss EJB 3.0と拡張機能

  JMXサービスオブジェクト
はじめに

JMX MBeanサービスはJBossアプリケーションサーバを形成する重要なサービスです。開発者は、MBeanサービス同士の依存関係を指定し、サーバ起動時に正しい順番でサービスが起動するように指定できます。また、これはサーバの内部サービスを実装するのに特に最適です。JBossの内部サービスの多くはMBeanとして実装されています。サービス同士は内部JMXバス(つまりJBoss JMXマイクロカーネル)を通してお互いに通信します。MBeanは、JBossの内部サービスを管理するJBoss管理者のための統一された管理インタフェースも提供します。

管理オブジェクトのプールから提供されるEJBサービスと異なり、JMX MBeanはサーバのJVMでシングルトンオブジェクトとして提供されます。サービスオブジェクトはステートフルで、アプリケーション全体で有効です。

MBeanサービスはとても有用ですが、開発は簡単ではありません。通常のJMXサーバ環境では、たくさんのフレームワーククラスを拡張し、リフレクションのようなAPIを使用しなければなりません。一方、JBoss EJB 3.0サーバでは簡単なアノテーションを使って、POJOをMBeanサービスにすることができます。このトレイルでは、EJB 3.0スタイルのMBeanサービスの開発について学びます。このトレイルで学ぶアノテーションはJBoss固有です。正式なEJB 3.0仕様の範囲には含まれていません。

サンプルアプリケーション

このトレイルでは、投資計算を行うMBeanサービスを作成します。サービスの管理的な側面を紹介するために、計算プログラムでは成長率は固定にしています。成長率は、管理者がJMX管理サーバを通して変更します。

クライアントアプリケーションは、JMX APIを使ってコンテナからMBeanのシングルトンオブジェクトの参照を取得し、計算サービスを利用します。下のボタンをクリックして、別ウィンドウで計算プログラムを起動してみてください。JSPページがセッションBeanにアクセスし、投資計算を行います。

計算プログラムの成長率を変更するには(つまり、サービスを管理するには)、JMX管理コンソールを使用します。通常、JMXコンソールはアクセス制限されているため、運用中のサーバでこの機能をお見せするのは困難です。そこで、フラッシュムービーを使って、管理コンソールで計算プログラムを管理し、成長率(利率)を変更するところをご覧いただきます。下のボタンをクリックしてムービーをご覧ください。

ご自分のサーバにTrailBlazerアプリケーションをデプロイし、JMXコンソールにアクセスできる場合は、http://localhost:8080/jmx-console/ページの下のほうにcalculator MBeanが見えるはずです。ページの最下部までスクロールしてください。また、calculate()メソッドに適切な引数を指定することによって、JMXコンソールから直接投資計算を行うこともできます。

MBean管理インタフェース

MBean管理インタフェースは、MBeanサービスの外向きのインタフェースです。MBeanサービスのクライアントやJMX管理コンソールからアクセス可能な属性やメソッドを公開します。EJB 3.0プログラミングモデルにおいては、MBean管理インタフェースはセッションBeanインタフェースと同じように、単なるJavaインタフェースです。以下のコードの抜粋では、Calculator インタフェースで、Growthrate属性とcalculate()メソッドを定義しています。


public interface Calculator {

  // Attribute
  public void setGrowthrate (double g);
  public double getGrowthrate ();

  // The management method
  public double calculate (int start, int end, double saving);

  // Life cycle method
  public void create () throws Exception;
  public void destroy () throws Exception;
}

管理インタフェースはMBeanのライフサイクルメソッドも定義します。以下のメソッドを組み合わせて定義します。

  • create() -- サービスと、依存しているすべてのサービスが生成されたときにサーバから呼ばれます。この時点では、サービス(および依存しているすべてのサービス)はJMXサーバにインストールされていますが、まだ機能しません。
  • start() -- サービスと、依存しているすべてのサービスが起動されたときにサーバから呼ばれます。この時点では、サービス(および依存しているすべてのサービス)は全機能が使用可能です。
  • stop() -- サービスが停止したときにサーバから呼ばれます。この時点では、サービス(およびそのサービスに依存しているすべてのサービス)はもはや機能しません。
  • destroy() -- サービスが破棄され、MBeanサーバから削除されるときにサーバから呼ばれます。
MBeanの実装

MBean実装クラスはMBean管理インタフェースを実装するだけです。JBossは@ServiceタグでアノテーションされたクラスをJMXサーバに登録します。アノテーションのobjectName属性で、このMBeanサービスが登録するサービス名を指定します。@Managementアノテーションで管理インタフェースを指定します。つまり、同じBeanクラスに対して、ローカルインタフェース、リモートインタフェース、管理インタフェースの複数のインタフェースを定義できるのです。JMXコンソールでは、trail:service=calculatorの名前でこのMBeanを参照できます。


@Service (objectName="trail:service=calculator")
@Management(Calculator.class)
public class CalculatorMBean implements Calculator {

  double growthrate;

  public void setGrowthrate (double growthrate) {
    this.growthrate = growthrate;
  }

  public double getGrowthrate () {
    return growthrate;
  }

  public double calculate (int start, int end, double saving) {
    double tmp =
        Math.pow(1. + growthrate / 12., 12. * (end - start) + 1);
    return saving * 12. * (tmp - 1) / growthrate;
  }

  // Lifecycle methods
  public void create() throws Exception {
    growthrate = 0.08;
    System.out.println("Calculator - Creating");
  }

  public void destroy() {
    System.out.println("Calculator - Destroying");
  }
}

MBeanサービスのシングルトンオブジェクトが生成されると、JMXサーバからcreate()メソッドが呼ばれ、Growthrate属性に初期値が設定されます。

MBeanサービスを使う

MBeanサービスを利用するには、まずサービス名でサービスのシングルトンオブジェクト(またはプロキシ)を検索します。JBoss JMXではこのような処理を行う以下のような便利なメソッドを用意しています。


private Calculator cal = null;

public void jspInit () {
    try {
        MBeanServer server = MBeanServerLocator.locate();

        cal = (Calculator) MBeanProxyExt.create(
            Calculator.class,
            "trail:service=calculator",
            server);
    } catch (Exception e) {
        e.printStackTrace ();
    }
}

ここで、MBeanサービスと管理メソッドを呼び出すことができます。


result = nf.format(cal.calculate(start, end, saving));
MBean間の依存関係

MBeanサービスの重要な機能のひとつは、MBean間の依存関係を指定して、他のサービスが正しく起動されている場合にのみ、あるサービスを起動するようにできることです。@Dependsアノテーションで、依存しているMBeanを指定します。


@Service (objectName="trail:service=investmentAdvisor")
@Depends ("trail:service=calculator")
public class InvestmentAdvisorMBean implements InvestmentAdvisor {
    // ... ...
}

あるいは、MBeanが依存するMBeanの一覧を指定することもできます。


@Service (objectName="trail:service=investmentAdvisor")
@Depends ({"trail:service=calculator",
           "trail:service=riskAnalysis"})
public class InvestmentAdvisorMBean implements InvestmentAdvisor {
    // ... ...
}

MBeanが持つ属性が別のMBeanの場合、その属性のセッターメソッドに@Dependsアノテーションを使用することで、コンテナは自動的に依存するMBeanオブジェクトに依存性を注入します(セッターの依存性注入)。下の例では、trail:service=calculatorのMBeanが起動されると、コンテナは適切な引数でsetCalculator()メソッドを呼びます。InvestmentAdvisorのMBeanのCalculator属性は、明示的なルックアップを行わなくても自動的に正しい値が設定されます。


@Service (objectName="trail:service=investmentAdvisor")
public class InvestmentAdvisorMBean implements InvestmentAdvisor {

    @Depends ("trail:service=calculator")
    public void setCalculator (Calculator calculator) {
      this.calculator = calculator;
    }

    // ... ...
}
ソースコード参照

JMXサーバ

JMXクライアント

まとめ

このトレイルでは、簡単なEJB 3.0スタイルのアノテーションを使ってJMX MBeanサービスを開発する方法を学びました。JBossアプリケーションサーバの内部サービスや他のコンポーネントに対して管理可能なサービスを提供するにはMBeanサービスはとても有効です。次のトレイルでは、もう一つのタイプのサービスであるメッセージ駆動型サービスについて議論します。