セッションBeanのライフサイクル
|
|
 |
セッションBeanのインスタンスは、EJBコンテナが生成し管理します。しかし時折Bean管理をカスタマイズしたい場合もあるでしょう。たとえば、Beanインスタンスの生成時に、あるフィールド変数に初期値を代入したり、あるいはBeanインスタンスが破棄される際に外部リソースのクローズ処理を行ったりしたい場合があるでしょう。このような場合は、Beanクラスにコールバックメソッドを用意し、Beanのライフサイクルのあらゆる場面でEJBコンテナにコールバックメソッドを呼び出させることができるのです。
古いEJB 2.1では、コールバックメソッドはフレームワークのインタフェースから継承していました。処理がなくても、これらのインタフェースを実装する必要がありました。これではコードは肥大化し読みにくくなってしまいます。EJB 3.0では、フレームワークのインタフェースはありません。簡単なアノテーションで、EJBクラスのどのメソッドでもライフサイクルのコールバックメソッドにすることができます。このトレイルでは、これらのアノテーションについて学びます。
|
|
|
 |
EJB 3.0の仕様では、Beanのライフサイクルの中で呼ばれるコールバックメソッドを指定するアノテーションがいくつか定義されています。EJBコンテナは、アノテーションされたメソッドをセッションBeanのライフサイクルの様々な場面で自動的に呼び出します。以下のアノテーションは、Beanクラスのどのメソッドにも使用できます。
@PostConstruct : Beanインスタンスがインスタンス化された直後にこのアノテーションが付いたメソッドが呼び出される。ステートレスセッションBeanにもステートフルセッションBeanにも使える。
@PreDestroy : オブジェクトプールから期限切れや未使用のBeanインスタンスが破棄される直前にこのアノテーションが付いたメソッドが呼び出される。ステートレスセッションBeanにもステートフルセッションBeanにも使える。
@PrePassivate : ステートフルセッションBeanが長い間使用されないと、コンテナはインスタンスを非活性化し状態をキャッシュに退避する場合がある。Beanインスタンスが非活性化される直前にこのアノテーションが付いたメソッドが呼び出される。ステートフルセッションBeanにのみ有効。
@PostActivate : 非活性化されたステートフルセッションBeanを再び使用すると、新たにインスタンスが作られ、Beanの状態が復元される。新たに復元されたBeanインスタンスが使用可能になるとこのアノテーションが付いたメソッドが呼び出される。ステートフルセッションBeanにのみ有効。
@Init : ステートフルセッションBeanの初期化メソッド。@PostConstruct アノテーションとの違いは、ステートフルセッションBeanには複数のメソッドに@Init を指定できる点である。しかし、各Beanインスタンスでは@Init メソッドは1回しか呼ばれない。EJB 3.0コンテナがどの@Init メソッドを呼ぶかは、Beanの生成方法によって異なる。(詳細はEJB 3.0の仕様を参照。)@Init メソッドの後、@PostConstruct メソッドが呼ばれる。
ステートフルセッションBeanのためのもう一つのライフサイクルメソッド用アノテーションは@Remove タグです。それはコールバックメソッドではありません。なぜなら、(コンテナでなく)アプリケーションがコンテナのオブジェクトプールからBeanインスタンスを削除するために、@Remove メソッドを呼び出すからです。
|
|
|
 |
このトレイルでは、セッションを使った投資計算プログラムに、セッション管理機能を持つように改変してみましょう。現在のセッションを終了し、別のセッションを開始してみてください。計算プログラムがセッションを処理した回数(つまり訪問者数)、そのうちのアクティブなセッション数、キャッシュに退避されたセッション数などがわかるはずです。下のボタンをクリックして新しい計算プログラムを実行してみてください。
|
|
|
 |
アプリケーションのWeb層(たとえば、JSPページ)は、セッションの最初で新たなステートフルセッションBeanを作成します。つまり、コンテナ内で新たなBeanインスタンスが生成されます。セッションBeanが生成されると、まずセッションの履歴を保持するArryList オブジェクトを初期化します。そして、静的なSessionRecord オブジェクト内の訪問者数と、アクティブなセッション数を1増加します。これらの処理は、@PostContruct アノテーションを指定したinitialize() メソッドが行います。
@Stateful
public class SessionCalculator implements Calculator, Serializable {
// ... ...
public ArrayList <Integer> starts, ends;
public ArrayList <Double> growthrates, savings, results;
@PostConstruct
public void initialize () {
starts = new ArrayList <Integer> ();
ends = new ArrayList <Integer> ();
growthrates = new ArrayList <Double> ();
savings = new ArrayList <Double> ();
results = new ArrayList <Double> ();
SessionRecord.totalSess++;
SessionRecord.activeSess++;
}
// ... ...
}
|
|
|
 |
ステートフルセッションBeanがメモリから非活性化されるときと、メモリに戻されるとき、静的なSessionRecord オブジェクト内のアクティブなセッション数を更新する必要があります。この処理はserialize() メソッドとactivate() メソッドが行います。
@Stateful
public class SessionCalculator implements Calculator {
// ... ...
@PrePassivate
public void serialize () {
SessionRecord.pausedSess++;
}
@PostActivate
public void activate () {
SessionRecord.pausedSess--;
}
// ... ...
}
|
|
|
 |
セッションが終了すると、Web層のHttpSession オブジェクトはやがて期限切れとなり、キャッシュされているステートフルセッションBeanはコンテナから破棄されます。@PreDestroy を指定したexit() メソッドで、アクティブなセッション数を減らします。
@Stateful
public class SessionCalculator implements Calculator {
// ... ...
@PreDestroy
public void exit () {
SessionRecord.activeSess--;
}
// ... ...
}
|
|
|
 |
アプリケーションがセッションの開始時にJNDI経由でステートフルセッションBeanのスタブを取得すると、サーバは新しいインスタンスを生成し、プールに置きます。セッションBeanはセッションが期限切れになると自動的に削除されます。しかし、期限が切れる前に明示的に別のセッションを開始したい場合はどうすれば良いでしょう?コンテナに強制的にBeanインスタンスを削除させるには@Remove アノテーションで指定したメソッドを明示的に呼びます。メソッド呼び出しが終わると、EJB 3.0コンテナは @PreDestroy メソッドがあれば呼び出し、インスタンスを削除します。このサンプルでは、@Remove メソッドは空です。メソッドはコンテナにインスタンスを削除するようにシグナルを送るだけです。
@Stateful
public class SessionCalculator implements Calculator {
// ... ...
@Remove
public void stopSession () {
// Call to this method signals the container
// to remove this bean instance and terminates
// the session.
}
// ... ...
}
以下のコードはJSPページから@Remove メソッドを呼ぶ例です。HttpSession のキャッシュを空にし、不要なスタブを削除することにも注意してください。
// "cal" is the stub of the stateful session bean.
// It is cached in the HttpSession's "lifecycle_cal" attribute
if ("Logout".equals(request.getParameter("action"))) {
cal.stopSession ();
session.setAttribute ("lifecycle_cal", null);
// ... ...
}
|
|
|
 |
これらすべてのコールバックメソッドを記述するとセッションBeanクラスが乱雑になってしまう場合は、コールバックリスナのクラスにコールバックメソッドを分離することもできます。セッションBeanクラスに@CallbackListener タグを指定し、リスナのクラス名をパラメタに記述します。
@Stateful
@CallbackListener(CalculatorCallbackListener.class)
public class SessionCalculator implements Calculator {
// ... ...
}
リスナクラスには、アノテーションされたコールバックメソッドをすべて記述します。ここではコールバックメソッドはBeanインスタンスを入力引数に持ちます。コンテナは、実行時にこのコールバックイベントの原因となるBeanインスタンスをコールバックメソッドに渡します。
public class CalculatorCallbackListener {
@PostConstruct
public initialize (CalculatorBean cal) {
// ... ...
}
@PreDestroy
public exit (CalculatorBean cal) {
// ... ...
}
}
|
|
|
 |
EJBサーバ
EJBクライアント
|
|
|
 |
このトレイルでは、セッションBeanのライフサイクルとコールバックメソッドについて議論しました。JBoss EJB 3.0サーバは、セッションBeanだけでなくEJB 3.0仕様にはない様々なタイプのサービスオブジェクトも管理します。次のトレイルでは、JBossアノテーションを使って容易にJMX MBeanサービスを記述する方法について議論しましょう。
|
|