February 27, 2008

EJB3でのホームインタフェースの作成

どのWebサイトや雑誌記事を見ても「EJB3ではホームインタフェース不要」と、書いてありますが・・・

Stateful SessionBeanのセッション管理をアプリケーションで制御したい場合にはホームインタフェースが必要になる場面も多いと思います。

具体的な例のひとつは、アプリケーションで一旦セッションを破棄して新規にセッションを開始したい場合です。

@EJBアノテーションはコンテナがフィールドを初期化する時にしか動作しないため、EJBのビジネスインタフェース型のフィールドを定義して、@EJBアノテーションを付与する方法では、このようなシチュエーションに対応できません。


EJB3でホームインタフェースを利用する場合は、次のように実装します。

ホームインタフェースを作成する。

  • javax.ejb.EJBLocalHome(リモート呼び出しを行う場合は javax.ejb.EJBHome)インタフェースを継承して作成する。
  • 1つ以上のcreate()メソッドを定義する。戻り値の型は次の手順で作成するビジネスインタフェースの型、引数は任意(と言ってもSerializableな型)、javax.ejb.CreateException をthrowするように実装する。
  • create()メソッドは引数の数と型が異なるものをいくつでもオーバーロード可。

package study.ejb3.model.service;

import javax.ejb.CreateException;
import javax.ejb.EJBLocalHome;

/**
 * ホームインタフェース。
 * javax.ejb.EJBLocalHome または javax.ejb.EJBHome を継承して作成する。
 * 1つ以上の create() メソッドを定義する。戻り値の型は ビジネスインタフェースの型。
 * create() メソッドは javax.ejb.CreateException をthrowするように定義する。
 * create() メソッドは引数の数と型が異なるものをいくつでもオーバーロード可。
 */
public interface HogeServiceHome extends EJBLocalHome {

    /**
     * create() メソッド
     */
    public HogeService create() throws CreateException;

}


ビジネスインタフェースを作成する。
  • 通常のEJB3ビジネスインタフェースとは違い、ホームインタフェースを併用する場合は javax.ejb.EJBLocalObject(リモート呼び出しを行う場合は javax.ejb.EJBObject)インタフェースを継承して作成する。
  • 任意のビジネスメソッドを定義する。ただし、引数と戻り値は Serializableな型であること。これは通常のEJB3スタイルと同様。
  • また、後述するBean実装クラスで@Removeアノテーションを付けたメソッドをクライアントから呼び出せるようにするため、同メソッドを定義する。


package study.ejb3.model.service;

import java.rmi.RemoteException;

import javax.ejb.EJBLocalObject;

/**
 * ビジネスインタフェース.
 * javax.ejb.EJBLocalObjectまたはjavax.ejb.EJBObjectを継承して作成する。
 * 任意のビジネスメソッドを定義する。戻り値と引数はSerializableな型であること。
 *
 */
public interface HogeService extends EJBLocalObject {

    /**
     * ビジネスメソッド
     */
    public String businessMethod() throws RemoteException;

    /**
     * Bean実装クラスで@Removeアノテーションを付けるメソッド
     */
    public void destroy() throws RemoteException;

}


Bean実装クラスを作成する。
  • 通常のEJB3スタイルとは異なり、ビジネスインタフェースをimplementsしない。
  • create() メソッドの引数の数と型に対応したメソッドを実装し、@Initアノテーションを付ける。メソッド名は任意。アクセス修飾子は public、戻り値の型は void 。
  • 任意の名前のメソッドを実装し、@Remove アノテーションを付ける。アクセス修飾子は public、戻り値の型は void。
  • ビジネスインタフェースに定義したビジネスメソッドを実装する。javax.ejb.EJBException をthrowするように実装する。
  • クラス宣言部に @Stateful アノテーションを付ける。これは通常の EJB3スタイルと同様。
  • クラス宣言部に@LocalHome(リモート呼び出しを行う場合は@RemoteHome)アノテーションを付ける。引数に、ホームインタフェースのクラスオブジェクトを指定する。
  • クラス宣言部に@Local(リモート呼び出しを行う場合は@Remote)アノテーションを付ける。引数に、ビジネスインタフェースのクラスオブジェクトを指定する。
  • 上記2つの設定により、ホームインタフェース、ビジネスインタフェース、Bean実装クラスの3つが関連付けられる。従来のEJB2.xではデプロイメントディスクリプタ(配備記述子)ejb-jar.xmlで設定した内容。


package study.ejb3.model.service;

import javax.ejb.EJBException;
import javax.ejb.Init;
import javax.ejb.Local;
import javax.ejb.LocalHome;
import javax.ejb.Remove;
import javax.ejb.Stateful;

/**
 * Bean実装クラス。
 * 通常のEJB3スタイルとは異なり、ビジネスインタフェースをimplementsしない。
 * @Local(または@Remove)アノテーションで
 *                          関連づくビジネスインタフェースを指定する。
 * @LocalHome(または@RemoveHome)アノテーションで
 *                          関連づくホームインタフェースを指定する。
 */
@Stateful(name = "HogeService")
@Local(HogeService.class)          // ビジネスインタフェースのクラスオブジェクトを指定
@LocalHome(HogeServiceHome.class) // ホームインタフェースのクラスオブジェクトを指定
public class HogeServiceBean {

    /**
     * ビジネスメソッド
     */
    public String businessMethod() throws EJBException {
        return "Hello! Business Method!";
    }

    /**
     * ホームオブジェクトのcreate()メソッドが呼ばれたとき
     * (新規セッション開始時)に呼ばれる
     */
    @Init
    public void init() {
        System.out.println("init() が呼ばれた");
    }

    /**
     * クライアントからこのメソッドが呼ばれるとセッションが破棄される
     */
    @Remove
    public void destroy() {
        System.out.println("destroy() が呼ばれた");
    }

}


EJBクライアント(EJB呼び出し側)の実装。
  • EJBビジネスインタフェース型ではなく、ホームインタフェース型のフィールドを定義し、@EJBアノテーションを付ける。EJBオブジェクトと同様、ホームオブジェクトも@EJBでインジェクション可能。


@EJB
private HogeServiceHome home;


  • ホームオブジェクトの create() メソッドを呼び出すと、EJBオブジェクトを取得可能。同時に新規にセッションが開始される。


// セッションを開始。
HogeService service = home.create();


  • EJBオブジェクトの、@Remove が付いたメソッドを呼び出すとセッション破棄。


// セッションを破棄
service.destroy();


  • 新規にセッションを開始したい場合(EJBオブジェクトを新規に取得したい)は、再度ホームオブジェクトの create() メソッドを呼び出せばOK。


// セッションを改めて新規に開始。
service = home.create();


@EJBアノテーションはフィールド初期化時にしか動作しないため、ホームインタフェースを使わないと新規にセッションを開始したい場合(EJBオブジェクトを新規に取得したい)は、JNDIルックアップするコードを書かないといけないことになります。



・・・なんだか、EJB2.xとEJB3のスタイルが混在した、えらく中途半端なコードになってしまいますね(^^;

0 コメント:

Post a Comment