Takashi Nishigaya
Nishigaya's Weblog
Profile
Takashi Nishigaya
Sr. Java Architect
SunJava Consulting
Professional Services Delivery
アーカイブ
« 12月 2009
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  
       
今日
Click me to subscribe
Search

Java.net
リンク
 
« Java EE 5チュートリアル:EJB... | メイン | Java EE 5チュートリアル:EJB... »
金曜日 7 07, 2006
EJB3 リモートとローカルでビジネス・インターフェースを共有する

前回のエントリの最後にふれたように、セッション・ビーンをリモートからもローカルからも呼び出せるようにするためには、リモート用とローカル用の2つのビジネス・インタフェースを用意する必要があります。

@Stateless
@Remote(CalcRemote.class) @Local(CalcLocal.class)
public class CalcImpl implements CalcRemote, CalcLocal {...}

ローカル用の一部のメソッドをリモート用には公開したくない場合は別ですが、ほとんどの場合、リモート用とローカル用には同じビジネス・メソッドのセットを定義したいと考えるでしょう。上記のように、同じメソッドのセットをもつ2つのインタフェースを用意しなければならないとすると、以下のようなデメリットが生じます。

リモートとローカルでEJB参照のためのインタフェースクラスが異なる
例えば、セッション・ビーンCalcImplにアクセスするのに、スタンドアロンクライアントでの参照型はCalcRemoteで、Web層のコンポーネントからはCalcLocalと使い分けなければなりません。EJBを多用した分散システムで、EJBモジュールのデプロイメント単位の構成変更により、ローカル呼出しからリモート呼出しに変更せざるをえなくなったとします。その場合、そのEJBの変数宣言箇所やメソッドの引数でEJB参照を渡している箇所などがクラス名変更の影響を受けるため、ソースコードの見直し作業が大変になります。
インタフェース仕様変更のメンテナンスの問題
もし、ビジネス・インタフェースのメソッド・シグネチャの仕様変更を適用する場合、変更箇所は実装クラス、ローカル・インタフェース、リモート・インタフェースの3ヶ所になります。ただし、リファクタリング機能のある開発ツールを使えばメソッド・シグネチャ変更の同期は簡単に行なえます([1])。
クラス数が不必要に増える
そもそも不必要にクラスの数が増えるのはなるべく避けたいと思うのが一般的な心情です。EJBの数がn個あれば、クラスの数は3n個以上必要になるわけです(EJB 2.xでは、5n個必要だったことを考えればだいぶ減りましたが)。

ローカルとリモートでインタフェース・クラスを共有できない仕様は、J2EE 1.4(EJB 2.1)のときも仕様上不可避の問題でしたが、J2EE 1.4でのEJB開発ではほとんどの場合XDocletが使用されていたと思います。XDocletはEJB実装からEJBインタフェースを自動生成できるため、EJB実装とEJBインタフェースの同期はそれほど問題にはなりませんでした。EJB 3.0ではビジネス・インタフェースがせっかくPOJI(Plain Old Java Interface)になったのですから、なんとか1つにまとめたいものです。

ローカルとリモートで1つのインタフェースを使用できないのは、EJBクライアント側でルックアップする(あるいは、インジェクションする)EJBのメタ情報を宣言するためのアノーテーション@EJBの仕様上の問題です。@EJBはデプロイメント記述子のリモート用<ejb-ref>とローカル用<ejb-local-ref>の両方にマッピングされるように仕様化されました。@EJBアノーテーションそのものには、ローカルかリモートかを明示するメンバがなく、@EJB.beanInterface要素のインタフェースクラスが@Remoteと@Localのどちらでアノーテーションされているかの情報に頼らざるをえなくなっています(@EJB.beanInterface要素が省略された場合、アノーテーションされている変数の型から決定します)。もし、EJB参照のためのアノーテーションが@EJBRefと@EJBLocalRefの2つが用意されていたか、@EJBにローカル/リモートが明示できるメンバ要素が含まれていれば、おそらく1つのビジネス・インタフェースをローカル/リモートで共通化することが可能だったのではないかと思います。

しかし、現状のEJB 3.0仕様のままでもこの問題を解決する方法が、A Java Programmer's Blog: Remote or Local interface? に紹介されています。これはなかなか良いアイデアです。つまり、リモート用とローカル用にはインタフェースクラスを用意するものの、それらで定義するメソッドは両方の親インタフェースに全て定義してしまえば良いというものです。そのままでは、インタフェース・クラスが3つに増えてしまいますが、インナー・クラス表現を使ってJavaのクラスファイルとしては1つにまとめてしまえるわけです。

package com.example;

public interface Calc {
    public int add(int i, int j);

    @javax.ejb.Remote
    public interface Remote extends Calc {
    }
    @javax.ejb.Local
    public interface Local extends Calc {
    }
}
package com.example;
import javax.ejb.Stateless;

@Stateless
public class CalcImpl implements Calc.Local, Calc.Remote {
    public int add(int i, int j) {
	return i + j;
    }
}

クライアント側でローカル/リモートのどちらのEJB参照を要求するかを明示するには、Calcのサブインタフェースを明示すれば良いわけです。@EJBでインジェクションする場合は以下のように記述すればよいことになります。

@EJB(beanInterface=Calc.Remote.class)
Calc calc1;  // リモート参照

@EJB(beanInterface=Calc.Local.class)
Calc calc2;  // ローカル参照

ローカル/リモートどちらを選んでも、EJB参照の型はCalcに統一でき、ソースコードも増えません。ローカル呼出しからリモート呼出しに切替える場合であっても、変更はアノーテーションの部分だけで、ソースのロジックを見直す必要はありません。また、ローカルだけに公開したいメソッドを追加したい場合でもCalc.Localインタフェースにそのメソッドを追加すれば対応できます。


[1] 例えば、NetBeans 5.xでは、ソースコードのエディタ・ペインで実装クラスのメソッド名で右クリックし、コンテキストメニューからRefactor > Rename...またはRefactor > Change Method Parameters...を選ぶことで、複数インタフェースでメソッドが重複している場合でも同期的に変更が適用できます。

Posted at 08:11午後 7 07, 2006 by Takashi Nishigaya in Java  |  投稿されたコメント[1]

投稿されたコメント:

cool

Posted by wow gold on 11月月 03日, 2008年 at 10:44 午前 JST #

コメント
  • HTML文法 不許可
« Java EE 5チュートリアル:EJB... | メイン | Java EE 5チュートリアル:EJB... »