カンバセーションスコープ
カンバセーション (会話) スコープはJBoss Seamが初めて提唱したスコープで、複数のリクエストにまたがって持続するスコープだ。
セッションスコープとの違いは、セッションスコープよりも持続時間が短く、1セッションユーザが複数作成する可能性があることだ。
たとえば「登録画面→入力確認画面→完了画面」のように、複数のリクエストから成る論理的に一つの処理を行う間、状態を保持するために使用する。その応用範囲は大きく、HTTPリダイレクトをまたがって状態を保持したり、Ajaxリクエストを何度も受け付ける場合などに威力を発揮する。
会話スコープを使用するには、Conversationクラスのbegin()とend()を明示的に呼び出す必要がある。
リスト11 RegisterUser.java
@Component
public class RegisterUser {
@In Conversation conversation;
public void init() {
conversation.begin();
...
}
public void complete() {
...
conversation.end();
}
}
カスタムスコープの作成
また、カスタマイズされたスコープを作成することも可能だ。現在のスレッドに限定したスコープ、メソッドの開始から終了までという短いスコープ、またはビジネスプロセス全体にわたって生存するスコープなど、さまざまな可能性が考えられる。
スコープの作成方法は、アノテーションとコンテキストを作成し、コンテナに登録する、という作業から成る。
「コンテキストとは何か」を言葉で表すのは難しいが、「現在実行中のコードに関連付けられているスコープ」とほぼ同義だと言える。HTTPリクエストによって実行されたメソッドのコンテキストからは、リクエストやセッション、アプリケーションと言ったスコープにアクセスできるということだ。
アノテーションの作成方法は非常に簡単で、@ScopeTypeを付与したアノテーションを作成するだけだ。
リスト12
@ScopeType
@Target({TYPE, METHOD})
@Retention(RUNTIME)
public @interface ThreadScoped {
}
コンテキストは、javax.webbeans.Contextインタフェースを実装したクラスを作成する。同インタフェースには、オブジェクトを取得するためのget()とオブジェクトを削除するためのremove()メソッドが定義されている。
リスト13
public class ThreadContext implements Context{
public T get(Component component, boolean create) {
// スレッドローカルなMapなどからオブジェクトを取得
T componentInstance = ...
if (componentInstance == null && create) {
componentInstance = component.create();
// スレッドローカルなMapなどにオブジェクトを保存
...
}
return componentInstance;
}
public void remove(Component component) {
// スレッドローカルなMapなどからオブジェクトを削除
...
}
}
あとは、コンテナに対してスコープを登録する。コンテナはjavax.webbeans.Containerインタフェースによって表現されており、リスト14のようなメソッドを持つ。
リスト14
public interface Container {
public void addContext(Class scopeType, Context context);
...
}
プログラムの任意の箇所で、addContext()メソッドを呼び出せば、コンテキストを登録できる。
リスト15
// 第一引数はアノテーションのクラス、第二引数はコンテキスト
container.addContext(ThreadScoped.class, new ThreadContext());
以降、アノテーションを付与したコンポーネントはそのスコープに関連付けられる。
リスト16
<strong>@ThreadScoped</strong>
@Component
public class CurrentTransaction {
...
}