minimize

事業拡大のため、新しい仲間を募集しています。
→詳しくはこちら

ここでは、Stateful Bean を使ってみます。
以下にコードを載せます。

Sample.java

import javax.ejb.Remote;
@Remote
public interface Sample {
    void add(int count);
    void show();
}

SampleBean.java

import javax.ejb.Stateful;
@Stateful
public class SampleBean implements Sample {
    private int total = 0;
    public void add(int count) {
        System.out.println("Add " + count);
        total += count;
    }
    public void show() {
        System.out.println("Total = " + total);
    }
}

Stateless Bean とほとんど同じです。
違うのは @Stateful というAnnotationを使っていること位です。

Statefulとは

そして、「Stateful」というくらいですから
このBeanは状態を持つことが出来ます。
具体的に言えば、フィールドを持つことが出来るという事です。

private int total = 0;

Stateless Bean では、EJB実装クラスにフィールドを定義することは出来ません。
正確に言えば、定義して使うことは可能ですが
フィールドの値が保持されることが「保証されません」。

EJBサーバは、状況に応じてStateless Beanを破棄したり生成したりします。
Stateful Beanは、クライアント側で指示しない限り破棄されることは無いので
フィールドの内容は保持されることが保証されます。

これだけ聞くと、Stateless Beanを使うメリットなど無いように思えますが
そんな事はありません。Stateless BeanはStateful Beanに比べて
圧倒的なパフォーマンスを誇ります。
EJBはただでさえパフォーマンスに難点があり、
出来るだけStateless Beanを使うことが推奨されていることは覚えておきましょう。

Clientプログラムの作成

public class Client {
    public static void main(String[] args) throws Exception {
        Context ctx = new InitialContext();
        Sample ejb = (Sample) ctx.lookup(Sample.class.getName());
        ejb.add(100);
        ejb.add(200);
        ejb.show();
    }
}

出力結果は以下のようになります。

Add 100
Add 200
Total = 300

Stateful Beanなので、最初のaddメソッド呼び出しから最後のshowメソッド呼び出しまで
ejbインスタンス内のcountフィールドは保持されることが保証されています。

一見、「そんなの当たり前じゃん」と思う方もいるかもしれません。
しかし、仮にこのBeanをStateless Beanで定義していた場合、このようにはなりません。
この場合、最初のaddメソッド呼び出し時のejbインスタンスと
2回名のaddメソッド呼び出し時のejbインスタンスは
同一とは限らないのです。

「そんな事あるか」って?これがあるんです。
countフィールドはejbインスタンスと直接結び付いておらず、
リモート呼び出しによる参照に過ぎません。
つまり、countフィールドの実体はClient側ではなくJBoss側に存在しています。

JBossはejb(Sampleインターフェイス)からのメソッド呼び出しがあると
JBoss側のBean(SampleBeanインスタンス)にアクセスしますが、
このBeanは必要に応じて破棄される可能性があります。

それに比べて、Stateful BeanはEJBサーバによって管理され
明示的な呼び出しが無い限りJBossはこのインスタンスを保持し続けます。
この管理の手間が、Stateful Beanの性能がStatelessよりも劣っている原因です。

Statelessの場合

仮に、上の例をStateless Beanで作ってみたらどうなるでしょうか?
例えば、以下のような結果になる可能性があります。

Add 100
Add 200
Total = 200

2回目のaddメソッド呼び出し時に、SampleBeanインスタンスが新規生成されたので
このときフィールドcountは0になってしまいました。
よって、add(200) の呼び出しによってcountは200になります。

実際には、このような単純な例で
SampleBeanインスタンスが破棄される可能性はまず無いのですが、
もしこのロジックが数分にも渡る長い処理だったり
他にたくさんのロジックがSampleBeanインスタンスを使っていた場合には
こういった事が起こる可能性があるのです。

プログラムの世界では、「失敗する可能性がある」という事は
「必ず失敗する」という事と同じ程度の認識が必要です。
つまり、こういったロジックを組んではいけません。