singleton セッション Bean の開発
Enterprise JavaBeans (EJB) 3.1 仕様によって導入された、singleton セッション Bean の Bean 実装クラスを作成します。EJB コンテナーは、singleton セッション Bean の 1 つのインスタンスのみを初期化し、そのインスタンスはすべてのクライアントによって共有されます。単一インスタンスはすべてのクライアントによって共有されるため、singleton セッション Bean は、特殊なライフサイクルおよび並行性セマンティクスを持ちます。
始める前に
このタスクについて
public interface Configuration {
Object get(String name);
void set (String name, Object value);
}
@Singleton
public class ConfigurationBean implements Configuration {
private Map<String, Object> settings = new HashMap<String, Object>();
public Object get(String name) {
return settings.get(name);
}
public void set(String name, Object value) {
settings.put(name,value);
}
}
他のエンタープライズ Bean タイプと同様、singleton セッション Bean の場合も、アノテーションを使用するのではなくデプロイメント記述子で、そのメタデータを宣言することができます。以下に例を示します。
<?xml version="1.0"?>
<ejb-jar
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"
version="3.1"
>
<enterprise-beans>
<ejb-name>ConfigurationBean</ejb-name>
<business-local>com.ibm.example.Configuration</business-local>
<ejb-class>com.ibm.example.ConfigurationBean</ejb-class>
<session-type>Singleton</session-type>
</enterprise-beans>
</ejb-jar>
手順
- 初期化メソッドおよび消滅メソッドをコード化し、トランザクション・コンテキストを設定するオプションとの関連性を理解します。 初期化中に、インスタンスが作成され、依存関係の注入が発生し、PostConstruct ライフサイクル・インターセプターのコールバックが開始されます。
収容アプリケーションが停止すると、singleton セッション Bean に対して PreDestroy ライフサイクル・インターセプターのコールバックが開始されます。
PostConstruct および PreDestroy のライフサイクル・インターセプターのコールバック中にトランザクション・アクティビティーを完了させると便利な場合があります。 singleton セッション Bean のライフサイクル・インターセプターのコールバックに、明確に定義されたトランザクション・コンテキストがあるのはこのためです。 以下のトランザクション・コンテキスト値は、@Timeout メソッドと類似しています。REQUIRED (デフォルト)、REQUIRES_NEW、および NOT_SUPPORTED のみを使用でき、REQUIRED は REQUIRES_NEW に変換されます。
トランザクション属性は、Bean クラスのライフサイクル・インターセプター・メソッドで指定されたときのみ認識されます。 同じトランザクション・コンテキストがすべてのライフサイクル・インターセプターに対して使用されます。 以下の例は、PostConstruct および PreDestroy ライフサイクル・インターセプター・コールバックにトランザクション属性が指定された singleton セッション Bean を示しています。
@Singleton public class ConfigurationBean implements Configuration { @PostConstruct @TransactionAttribute(REQUIRED) // the default; specified for illustration public void initialize() { // ... } @PreDestroy @TransactionAttribute(NOT_SUPPORTED) public void destroy() { // ... } // ... }
アノテーションを使用する代わりに、XML デプロイメント記述子を使用して同じメタデータを指定できます。 XML デプロイメント記述子でトランザクション属性を指定した場合、@TransactionAttribute アノテーションから取得したメタデータはいずれも無視されます。 以下の例では、前の例と同じメタデータを指定するために、XML デプロイメント記述子を使用します。
<assembly-descriptor> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>initialize</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <container-transaction> <method> <ejb-name>ConfigurationBean</ejb-name> <method-name>destroy</method-name> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor>
- 特に指定されている場合を除き、singleton セッション Bean インスタンスは通常、Bean がクライアント・ビューの 1 つを通じて最初に使用されるときに初期化されます。これはその他のセッション Bean の場合と同じです。 Bean を開始 Bean としてマークするには、@Startup アノテーションまたは対応する XML デプロイメント記述子を使用します。
singleton Bean を開始 Bean としてマークを付けると、EJB コンテナーは、アプリケーションへの外部クライアント要求の実行を支援する前に、PostConstruct メソッドを実行する必要があります。
singleton Bean 内の PostConstruct メソッドは、EJB タイマーを作成したり、メッセージを JMS キューまたはトピックに追加したり、非同期 EJB メソッドを呼び出したり、EJB を呼び出す他の非同期メカニズムを開始したりすることができます。
ただし、デッドロックを避けるために、PostConstruct メソッドで、EJB タイマーの実行、メッセージ駆動型 Bean メソッドの呼び出し、および非同期 EJB メソッドの完了を待機してはなりません。
アプリケーション開発者は、これらの開始 singleton インスタンスの PostConstruct メソッドにビジネス・ロジックを配置して、クライアント処理 (キャッシュのプリロードやアプリケーション内の非同期処理の開始など) がコンテナーによって開始される前に実行する必要があるタスクを完了できます。
以下の例は、開始時の初期化が指定された singleton セッション Bean を示したものです。
@Singleton @Startup public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // 1. Create the database table if it does not exist. // 2. Initialize settings from the database table. // 3. Load a cache. // 4. Initiate asynchronous work (for example, work to a messaging queue or to // calls to asynchronous session bean methods. } // ... }
アノテーションを使用する代わりに、XML デプロイメント記述子を使用して同じメタデータを指定できます。 この singleton Bean を開始 singleton としてマークするには true を指定します。 逆に、クラス・ファイルに @Startup アノテーションが存在する場合は、false を指定すると、@Startup アノテーションはオーバーライドされます。
<session> <ejb-name>ConfigurationBean</ejb-name> <init-on-startup>true</init-on-startup> </session>
- singleton セッション Bean の初期化メソッドが別の singleton セッション Bean に暗黙的に依存しているかどうかを調べます。
暗黙的依存関係が存在する場合は、依存関係メタデータを使用して暗黙的依存関係を明示的依存関係にしてください。 コンテナーは、従属 Bean が初期化される前に依存関係 singleton Bean が初期化され、従属 Bean が破棄された後に依存関係 singleton Bean が破棄されるようにします。 以下の例は、依存関係メタデータを含む singleton セッション Bean を示しています。
@Singleton public class DatabaseBean { @PostConstruct public void initialize() { // Create database tables. } } @Singleton @DependsOn({"DatabaseBean"}) public class ConfigurationBean implements Configuration { @PostConstruct public void initialize() { // Initialize settings from a database table. } // ... }
さらに、ejb-link module.jar#bean 構文を使用することによって、モジュール間の依存関係を設定することができます。 循環する依存関係はサポートされていないため、そのような依存関係はアプリケーションが失敗する 原因になります。
アノテーションを使用する代わりに、XML デプロイメント記述子を使用して同じメタデータを指定できます。 XML デプロイメント記述子で依存関係メタデータを指定した場合、@DependsOn アノテーションからのメタデータはいずれも無視されます。
<session> <ejb-name>ConfigurationBean</ejb-name> <depends-on> <ejb-name>DatabaseBean</ejb-name> </depends-on> </session>
- コンテナー管理の並行性と Bean 管理の並行性のどちらを使用するかを決定します。 @Lock アノテーションおよび @AccessTimeout アノテーションは、Bean 管理の並行性を使用した場合は適用できません。
@ConcurrencyManagement アノテーションは singleton セッション Bean クラス上でのみ実装できます。 継承するクラス、またはクラス継承ツリーの上位クラスでは使用できません。
以下のサンプル・コードでは、Bean 管理の並行性を持つ singleton を示しています。@Singleton @ConcurrencyManagement(BEAN) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); synchronized public Object get(String name) { return settings.get(name); } synchronized public void set(String name, Object value) { settings.put(name, value); } }
アノテーションを使用する代わりに、XML デプロイメント記述子を使用して同じメタデータを指定できます。XML デプロイメント記述子でメタデータを指定し、その上さらに @ConcurrencyManagement アノテーションを使用してメタデータを指定する場合は、値を一致させる必要があります。そうしないと、アプリケーションは失敗します。 以下の例では、前の例と同じメタデータを指定するために、XML デプロイメント記述子を使用します。
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrency-management-type>Bean</concurrency-management-type> </session>
コンテナーは、呼び出された各メソッドに対してロックを実行しません。 要求されるロックは、実際の Bean によって実行されます。 サンプルでは、Bean プロバイダーが同期キーワードを使用したメソッドを実装するよう選択しています。 これは、Bean 管理の並行性を使用した singleton セッション Bean についてサポートされますが、他の EJB コンポーネント・タイプではサポートされません。 Bean プロバイダーは、同期キーワードを使用して並行性を提供する必要はありません。 例えば、Bean プロバイダーは、JDK 5 以降に存在する java.util.concurrent.locks.ReentrantReadWriteLock クラスを利用することができます。
コンテナー管理の並行性で EJB 3.1 仕様によって必要とされるロックのセマンティクスは、java.util.concurrent.locks.ReentrantReadWriteLock クラスの振る舞いに一致します。
- コンテナー管理の並行性を使用している場合は、メソッドの並行性の管理に @Lock 表記を使用します。 以下のサンプル・コードでは、コンテナー管理の並行性を持つ singleton を示しています。
@Singleton public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); @Lock(READ) public Object get(String name) { return settings.get(name); } public void set(String name, Object value) { settings.put(name, value); } }
アノテーションを使用する代わりに、XML デプロイメント記述子を使用して同じメタデータを指定できます。XML デプロイメント記述子と @Lock アノテーションの両方でメタデータが指定されていると、@Lock アノテーションから取得したメタデータは無視されます。 以下の例では、前の例と同じメタデータを指定するために、XML デプロイメント記述子を使用します。
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> </concurrent-method> </session>
このサンプルでは、メソッドの開始時にコンテナーが読み取りロックを取得する必要があることを示す、メソッドへの @Lock(READ) アノテーションも示しています。 メソッドに @Lock アノテーションが付加されると、クラス・レベルで指定された @Lock アノテーションがオーバーライドされます。 クラス・レベルの @Lock アノテーションがない場合は、デフォルトの書き込みロックが適用されます。 サンプルでは、メソッドの @Lock(READ) がクラス・レベルのデフォルトの書き込みロックをオーバーライドしています。メソッドにメソッド・レベルのアノテーションが付加されておらず、クラス・レベルのアノテーションがない場合、コンテナーではデフォルトの書き込みロックが使用されます。
多くのメソッドが読み取りロックを必要とするため、@Lock(READ) をクラス・レベルで使用して、このクラスのすべてのビジネス・メソッドが読み取りロックを取得するためにコンテナーを必要としていることを示します。 書き込みロックを必要とするメソッドでは、クラス・レベルで指定された読み取りロックをオーバーライドすることを示すために、これらのメソッドに @Lock(WRITE) を使用してアノテーションを付けます。
以下の例は、この手法を示しています。
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { private Map<String, Object> settings = new HashMap<String, Object>(); public Object get(String name) { return settings.get(name); } @Lock(WRITE) public void set(String name, Object value) { settings.put(name, value); } }
@Lock アノテーションは、@Lock アノテーションと同じクラスで宣言されたメソッドにのみ適用されます。 特定のクラスにおいて、@Lock のメタデータがクラス継承ツリーの上位クラスから継承されることはありません。アノテーションをクラス・レベルで使用する代わりに、あらゆるメソッド名と一致する特殊メソッド名 * を使用すれば、同じメタデータを XML デプロイメント記述子で指定することができます。
- コンテナー管理の並行性を使用している場合は、@AccessTimeout 表記を使用して、ロックが認可されるまでのメソッドの待機時間を制限します。 以下のサンプル・コードは、同時アクセスのタイムアウトを示しています。
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) @AccessTimeout(1000) public Object get(String name) { // query the database } public void set(String name, Object value) { // update the database } }
アノテーションが提供されていない場合、デフォルトでは、メソッドはロックが認可されるまで待機します。 ロックが認可されるまでのクライアントの待機時間に制限はありません。 クラス・レベルでコード化されているものはないため、クラスのすべてのメソッドにロックが認可されるまでの待機時間に制限はありません。 @AccessTimeout アノテーションが使用され、指定された制限時間内にコンテナーがロックを認可できない場合、クライアントに javax.ejb.ConcurrentAccessTimeoutException がスローされます。 @AccessTimeout アノテーションは、@AccessTimeout アノテーションがあるのと同じクラス内で 宣言されたメソッドにのみ適用されます。特定のクラスにおいて、@AccessTimeout アノテーションのメタデータがクラス継承ツリーの上位クラスから継承されることはありません。
@Lock アノテーションと同様、@AccessTimeout アノテーションも XML デプロイメント記述子を使用して指定できますが、XML デプロイメント記述子を使用すると、@AccessTimeout アノテーションからのメタデータは無視されます。 以下の例では、前の例と同じメタデータを指定するために、XML デプロイメント記述子を使用します。
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>get</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>1000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
- concurrent-methodType の XML コーディングは EJB 仕様に概説されている、container-transaction メソッド・エレメントの XML を作成するための 3 つのスタイルに従うことを知っておくことが重要です。
lock エレメントと access-timeout エレメントは両方ともオプションであることを覚えておいてください。 この 3 つのスタイルは次のように説明されます。
スタイル 1 は、特殊メソッド名 * を使用して、ロック・タイプ、アクセス・タイムアウト値、またはその両方を、指定された Bean のすべてのビジネス・メソッドに適用します。
<!-- Example: Style 1 --> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
スタイル 2 は、特定の名前を持つビジネス・メソッドを参照し、それを指定されたロック・タイプ、アクセス・タイムアウト値、またはその両方に割り当てるために使用されます。 メソッド名が多重定義されている場合、つまり名前は同じだがメソッド・シグニチャーが異なるメソッドが複数ある場合、その名前のメソッドはいずれも指定されたロック・タイプ、アクセス・タイムアウト値、またはその両方を持ちます。 スタイル 2 はスタイル 1 よりも優先されます。
<!-- Example: Style 2 --> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
スタイル 3 は、指定されたメソッド名と一致し、かつリストされているメソッド・パラメーターと一致するメソッド・シグニチャーを持つ、別個のメソッドを参照するために使用されます。 スタイル 3 はスタイル 1 よりもスタイル 2 よりも優先されます。
<!-- Example: Style 3 --> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <lock>Read</lock> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method>
スタイル 1 XML がロック・タイプを定義するために使用された場合は、Bean 上のすべての @Lock アノテーションが無視されます。 同じことがアクセス・タイムアウトにも当てはまります。 スタイル 1 XML がアクセス・タイムアウト値を定義するために使用された場合は、Bean 上のすべての @AccessTimeout アノテーションが無視されます。
- @Lock および @AccessTimeout アノテーションは、各アノテーションの対応する XML デプロイメント記述子コードとして、互いに無関係に扱われることを理解しておくことが重要です。
この概念を導入することにはいくつかの利点があります。 このようにロック・タイプとアクセス・タイムアウトを分離することは、ロック・タイプを知る必要がなくなることでブラック・ボックス・アプリケーション・コードに悪影響を与えないようにするのに役立ちます。 ロック・タイプ値に手をつけなくても差し支えなく、環境の要件にのみ適したアクセス・タイムアウト値を調整して、起こり得るデッドロック状態やその他の並行性問題を回避することができます。
ベンダー提供の EJB アプリケーションが実行されているが、システムのスローダウンのために頻繁にタイムアウトが発生するという シナリオを想定します。ロック・ロジックを変更するとデッドロック状態を引き起こす恐れがあるので、これは行わずにタイムアウト制限を変更します。 このような場合、デプロイメント記述子を編集し、変更したいメソッドに対して、必要なアクセス・タイムアウト値を指定できます。以下の例は、 Bean 実装にメソッド・レベルの @Lock(READ) アノテーションのみを指定し、 スタイル 2 の XML 作成方法を使用して access-timeout エレメント を 2,000 ミリ秒に設定する方法を示しています (オプションの lock エレメントは 指定していません)。結果は、アクセス・タイムアウトが 2,000 ミリ秒である読み取りロックを持つメソッドです。
@Singleton public class ConfigurationBean implements Configuration { @Lock(READ) public Object businessMethod(long value) { // ... } // ... }
同様に、以下の例で示すように、クラス・レベルでロック・アノテーションを使用し、スタイル 2、スタイル 3、またはその両方を使用して、XML で希望するアクセス・タイムアウト値を指定できます。<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } public Object businessMethod(long value, int i, Object value) { // ... } public Object businessMethod(long value, int i) { // ... } }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> <method-params> <method-param>long</method-param> <method-param>int</method-param> </method-params> </method> <access-timeout> <timeout>8000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
上記のコード例では、「businessMethod」という名前のすべてのメソッドについて、ロック・タイプが読み取りに、アクセス・タイムアウトが 2,000 ミリ秒になります。 ただし、メソッド「businessMethod」のインスタンスのうち、最初のパラメーターが long 型で 2 番目のパラメーターが int 型であるメソッド・シグニチャーを持つインスタンスを除きます。 メソッド「businessMethod」のこのインスタンスのロック・タイプは読み取りになりますが、アクセス・タイムアウトは 8,000 ミリ秒になります。
同じ原則は、スタイル 1 XML を使用してロック・タイプのみを定義するときにも適用されますが、アクセス・タイムアウト値には適用されません。 スタイル 2、スタイル 3、またはその両方を使用して、特定のメソッドまたは複数のメソッドにアクセス・タイムアウト値を追加することで、特定のロック・タイプとアクセス・タイムアウト値の結果を得ることができます。 以下の 例は、この点を示しています。<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <lock>Read</lock> </concurrent-method> <concurrent-method> <method> <method-name>businessMethod</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
上記のコード例では、ロック・タイプが読み取りでメソッド名が businessMethod であるすべてのビジネス・メソッドのロック・タイプが読み取りに、アクセス・タイムアウトが 2,000 ミリ秒になります。
また、クラス・レベルの @Lock アノテーションを指定してすべてのメソッドのロック・タイプを設定したり、スタイル 1 を使用してすべてのメソッドについてアクセス・タイムアウト値のみを設定する XML を作成することができます。 以下の例を参照してください。@Singleton @Lock(READ) public class ConfigurationBean implements Configuration { public Object businessMethod(long value) { // ... } // ... }
<session> <ejb-name>ConfigurationBean</ejb-name> <concurrent-method> <method> <method-name>*</method-name> </method> <access-timeout> <timeout>2000</timeout> <unit>Milliseconds</unit> </access-timeout> </concurrent-method> </session>
上記の例では、ConfigurationBean という Bean のすべてのビジネス・メソッドについて、ロック・タイプが読み取りに、アクセス・タイムアウト値が 2,000 ミリ秒になります。
- 使用したアノテーションの継承ルールを確実に理解するようにしてください。
- 読み取りロック・メソッドが、同じ singleton セッション Bean の書き込みロック・メソッドを呼び出す場合に発生する、再入可能なロックの振る舞いを回避してください。
singleton セッション Bean のビジネス・メソッドが、直接的または間接的に singleton セッション Bean の別のビジネス・メソッドを開始するとします。 最初のメソッドが書き込みロック・メソッドである場合、そのメソッドは特別な考慮事項なしに singleton セッション Bean のその他のビジネス・メソッドを呼び出すことができます。 ただし、同じ singleton セッション Bean クラスの別のビジネス・メソッド (書き込みロック・メソッド) を呼び出す場合は、読み取りロック・メソッドを慎重に実装するようにします。 この場合、javax.ejb.IllegalLoopbackException 例外が発生します。
サブトピック
singleton セッション Bean のロック・ポリシーの変更
この作業は、サーバー内でのすべての singleton セッション Bean の書き込みロックに対するデフォルトの不公平なロック・ポリシーをオーバーライドする場合に行います。この作業は、不公平なポリシーに従って singleton セッション Bean メソッド呼び出しの要求をロックすることを希望しない WebSphere® Application Server ユーザーを対象としています。singleton セッション Bean のロック・ポリシーの変更
この作業は、サーバー内でのすべての singleton セッション Bean の書き込みロックに対するデフォルトの不公平なロック・ポリシーをオーバーライドする場合に行います。この作業は、不公平なポリシーに従って singleton セッション Bean メソッド呼び出しの要求をロックすることを希望しない WebSphere Application Server ユーザーを対象としています。


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tejb_ssb
ファイル名:tejb_ssb.html