非同期要求ディスパッチャー・アプリケーションの設計に関する考慮事項
非同期要求ディスパッチャー (ARD) は、サーブレット・プログラミングの万能のソリューションではありません。アプリケーションのニーズと ARD を使用するに当たっての警告を評価する必要があります。すべてのインクルードを切り替えて非同期的に開始するのは、すべてのシナリオに当てはまるソリューションではありませんが、使い方が適切であれば ARD は応答時間を増やすことができます。
非同期要求ディスパッチャーのクライアント・サイドの実装
- JavaScript は応答出力に動的に書き込まれます。
- この JavaScript では、Ajax 要求がサーバー・サイドの結果プロバイダーに返されます。
- チャネルの非同期入出力 (AIO) 機能が原因で、Ajax 要求はスレッドとは連動せず、その代わりに完了はインクルード・コールバックを介して通知されます。
- クライアントは、ブラウザーの接続数の制限により、非同期インクルードに対して一度に 1 つの要求しか出しません。
- 元の接続は、インクルードの存続期間は有効でなければなりません。この接続を Ajax 要求に再使用することはできません。
- 以下のようなコメント・ノードは、
ブラウザー・オブジェクト・モデルに配置されます。コメント・ノードはページ・レイアウトには影響しないからです。<!--uniquePlaceholderID--><!--1-->
- 完全なフラグメントが存在する場合は、常に応答をクライアントに送ることができ、同じ ID を持つコメント・ノードが置き換えられます。すべてのフラグメントが取り出されるまで要求は行われません。
- クライアント・サイド集約を使用している場合は、サポートされているすべてのブラウザーでアプリケーションを検証してください。 アプリケーションがメソッド名 getDynamicDataIBMARD を使用しないようにするだけで済むように、オブジェクト指向 JavaScript の原則が使用されます。以前に指定された window.onload はすべて、ARD の onload メソッドの前に開始されます。
非同期要求ディスパッチャーのチャネル結果サービス
非同期 JavaScript コードからの、インクルード・データに対する要求は、Web コンテナー要求処理を介さないようにするために ARD チャネルが代行受信できる既知の Uniform Resource Identifiers (URL とも呼ばれる URI) に送られます。 これらの URI は、サーバーの再始動ごとに固有です。
例えば、 /IBMARD01234567/asyncInclude.js は、結果を強制的に取り出す JavaScript の URI で、/IBMARD01234567/IBMARDQueryStringEntries?=12000 は、ID 12000 を持つエントリーに対する結果を取り出します。
認証されていない結果へのアクセスを防止するために、サービス URI および ARD エントリーに対して固有 ID が生成されます。セッションと ARD の間では共通 ID ジェネレーターが共有されるため、固有性はセッション構成によって構成可能です。セッション ID はセキュアであると考えられていますが、Lightweight Third-Party Authentication (LTPA) トークンを使用する場合ほどセキュアではありません。
カスタムのクライアント・サイド集約
<!--uniquePlaceholderID--><!--x-->
ここで、x はインクルードの順序です。結果を取り出すためのエンドポイントは、要求属性 com.ibm.websphere.webcontainer.ard.endpointURI から取り出されます。<div id="2"><BR>Servlet 3--dispatcher3 requesting Servlet3 to sleep for 0 seconds at: 1187967704265
<BR> Servlet 3--Okay, all done! This should print pop up: third at: 1187967704281 </div>
AsyncRequestDispatcherConfig インターフェースと AsyncRequestDispatcher インターフェースについて詳しくは、アプリケーション・プログラミング・インターフェース (API) 文書の『com.ibm.websphere.webcontainer.async パッケージ』を参照してください。 生成された API 文書は、文書目次で、
の順にたどって入手できます。サーバー・サイド集約
クライアント・サイド集約と同様、サーバー・サイド集約も ARD チャネルを結果サービスとして使用します。ARD チャネルは、特定のバッファー・セットに対してどの非同期インクルードが発生したのかが分かっています。したがって、それらのバッファーでインクルード・プレースホルダーを検索することができます。JSP バッファリングの問題が原因で、インクルードのプレースホルダーが検索対象のバッファーにないことがあります。その場合は、次のバッファー・セットも、前のセットで欠落していたインクルード・プレースホルダーを探す必要があります。ARD は、応答内容をできるだけ早くクライアントに送信できるよう、インクルードが戻ると集約を繰り返し行おうとします。
並行性
インクルードの開始には作業マネージャーが使用されます。現在要求されているインクルードの数が、作業マネージャーの最大スレッド・プール・サイズよりも大きく、このサイズを大きくできない場合、作業マネージャーは現行のスレッドで作業を開始し、プレースホルダーの書き込みをスキップします。Concurrency Utilities for Java™ EE を使用すると、元のスレッドの Java EE コンテキストの伝搬が可能になります。 これには、作業域、国際化対応、アプリケーション・プロファイル、z/OS® オペレーション・システムのワークロード管理、セキュリティー、トランザクション、接続コンテキストなどが含まれます。
タイマー
ARD には単一のタイマーが使用され、ARD 要求のすべてのタイムアウト・タイプにはタイマー・タスクが作成されます。タイマーに登録したタスクが、指定された正確な時刻に実行されるとは限りません。これはタイマーが単一スレッドで実行されるため、あるタイムアウトが発生しても、別のタイムアウトのアクションが完了するまで待機することが必要な場合があるためです。タイマーは最後の手段として使用されます。
リモート要求ディスパッチャー
オプションで、ARD をリモート要求ディスパッチャーと連携させて使用することができます。リモート要求ディスパッチャーは、コア・グループ内の別のアプリケーションでインクルードを実行します。それを行うために、要求コンテキストを SOAP メッセージにシリアライズし、Web サービスを使用してリモート・サーバーを呼び出します。これは、SOAP メッセージを作成し、それを Web サービスを介して送信する時のコストが、要求をローカルに発行する時のコストよりも少ない場合に役立ちます。
例外
組み込まれているサーブレットで例外が発生した場合、Web コンテナーは例外のタイプにマップされているエラー・ページ定義を調べます。したがって、デプロイメント記述子で定義されたエラー・ページが、集約ページの一部として表示されます。インクルードに対する動作が異なる場合は、エラー・ページそれ自体にロジックを挿入します。インクルードは非同期に実行するため、 最上位のサーブレットがもうサービス中でない可能性があり、従って通常のインクルードのように非同期インクルードから例外が伝搬されて返されることはありません。その他のインクルードは、部分ページを表示できるようにするために終了します。
ARD 作業マネージャーのワーカー・スレッドが不足すると、非同期インクルードは同期インクルードのように処理されます。これがデフォルト設定ですが、この状態に陥らないよう、作業マネージャーを大きくすることもできます。 このような処理の変更は、処理中はユーザーからは不可視ですが、システム・ログには一度だけ警告として記録され、その後は、トレースが有効になっていればトレース・ログに記録されます。インクルードを同期的に行うことのできるその他の状態では、時間とともに期限切れになった要求が最大パーセンテージに達し、結果ストアが最大サイズに達します。
例外が通常のエラー・ページ処理の有効範囲外で発生する場合があります。例えば、作業マネージャーが作業を拒否することがあります。インクルード応答が戻るのを待っている間に、タイマーが期限切れになることがあります。結果を取り出すための汎用サービスとして動作する ARD チャネルが、無効な ID を受け取ることがあります。これらの場合は、ServletRequest、ServletResponse、および ServletContext などの、要求が動作するためのコンテキストが欠落しているため、エラー・ページ処理へのパスが存在しません。これらの問題を軽減するために、AsyncRequestDispatcherConfig インターフェースを使用して、カスタム・エラー・メッセージを提供できます。デフォルトが提供され、必要に応じて、国際化対応されます。
例外は、例えば後続のクライアント・サイドの XMLHttpRequests のような、カスタム構成が設定されている要求の有効範囲外で発生することもあります。この場合は、グローバル構成を変更する必要があります。グローバル構成は、com.ibm.wsspi.ard.AsyncRequestDispatcherConfigImpl.getRef() を使用して取り出せます。
- インクルードの開始
- 作業マネージャーは、インクルードが開始するのを待っている時間に対してタイムアウトを設定します。タイムアウトは、通常は即時に発生するため、プログラムでこれを使用可能にすることはできません。ただし、タイムアウトは作業マネージャーの設定で構成できます。 デフォルトでは、作業のスケジューリングの前に最大スレッド検査が行われるため、これは発生しません。使用中の AsyncRequestDispatcherConfig で setRetriable(true) が呼び出された場合は、作業を再試行できます。
- インクルードの終了
- 起動されたタイムアウトは、作業が受け入れられた後に開始します。このタイムアウトは、AsyncRequestDispatcherConfig.setExecutionTimeoutOverride メソッドを使用して、コンソールまたはプログラムで構成できます。デフォルト値は 60000 ms、すなわち 1 分です。インクルード結果の代わりに、AsyncRequestDispatcherConfig.setExecutionTimeoutMessage からのメッセージが送信されます。この起動済みのタイムアウトに達しても、データをフラッシュできるようになった時点で実際のインクルード結果が準備できている場合は、実際の結果が優先されます。また、このことは、常にインクルードが完了するまで待機する insertFragmentBlocking 呼び出しには適用されません。
- 結果の期限切れ
- クライアント・サイドは Ajax 要求に対して送信するためにサービスでの結果を保持しなければならないため、クライアントがダウンして当該エントリーを取り出すことがない場合に結果を期限切れにする方法が必要です。Ajax 要求は、応答を送信した直後に送られてくるため、一般的な要求に対してはデフォルトの 1 分で十分です。タイマーは、AsyncRequestDispatcherConfig の setExpirationTimeoutOverride メソッドを使用してプログラマチックに構成できます。期限切れになり、キャッシュから除去されたエントリーに誰かがアクセスしようとすると、AsyncRequestDispatcherConfig の getOutputRetrievalFailureMessage メソッドからメッセージが表示されます。このメッセージは、存在しない ID を使用して結果を要求した人に送られるのと同じメッセージです。
インクルードまたはフラグメント
非同期的に実行できるのはどの操作か、およびいつそれらの操作を開始できるのかを検討してください。要求の開始段階で getFragment 呼び出しが行われるときにはすべてのインクルードが完了していることが理想的です。そうすれば、インクルードが完了するまでの時間を十分にとれ、フラグメントの挿入時に追加のバッファリングや集約はあまり発生しなくなります。ただし、非同期インクルードを呼び出す方がもっと簡単です。これは通常の要求ディスパッチャー・インクルードと同じパターンに従うためです。
Web コンテナー (Web container)
- ServletContext
- コンテキスト間インクルードを実行する場合は、そのインクルードのターゲットであるコンテキストも ARD を使用可能にしておく必要があります。その理由は、Web アプリケーションのサーブレット・コンテキストが AsyncRequestDispatcher を取り出すための有効なメソッドを持つためには、その Web アプリケーションが ARD に対して初期化されている必要があるからです。集約タイプを混合させることができないため、集約タイプは、元のコンテキストの構成によって決定されます。
- ServletRequest
- インクルードごとに要求を複製する必要があります。そうしないと、スレッド間で競合が発生する可能性があります。アプリケーションはデフォルトの要求オブジェクトをラップできるため、ラッパーは com.ibm.wsspi.webcontainer.servlet.IServletRequest インターフェースをラップする必要があります。このインターフェースは、CloneNotSupportedException を作成する、パブリックな Object クローン・メソッドを持っています。
- このインターフェースを実装している要求ラッパーが見つかるまで、アンラップが行われます。未実装ラッパーは失われます。ただし、インクルードに対して構成されているサーブレット・フィルターは、応答を再ラップできます。
- ServletRequest に対して行われた変更は、AsyncRequestDispatcherConfig の transferState が有効になり、insertFragmentBlocking が呼び出されるまでは、最上位のサーブレットには伝搬されません。
- ServletResponse
- 応答出力は、元の応答がそのライフサイクルを終えても取り出すことができなければならないため、com.ibm.websphere.servlet.response.StoredResponse を拡張するラップされた応答が ARD によって作成され、インクルードに送信されます。
- 非同期インクルード内で設定されている内部ヘッダーは、ライフサイクル制限のため、AsyncRequestDispatcher の transferState が有効になり、insertFragmentBlocking が呼び出されるまではサポートされません。通常のヘッダーは、サーブレット仕様で指定されているとおり、同期インクルードではサポートされません。
- インクルード・フィルターは、新しい応答を再ラップでき、完了と同時にフラッシュする必要があります。
- ServletInputStream
- getParameter を使用してパラメーターを読み取るアプリケーションは問題を起こしません。最初の非同期インクルードの前にパラメーターの解析が強制的に行われ、入力ストリームへの同時アクセスが防止されます。
- HttpSession
- Set-Cookie ヘッダーが作成される初期 getSession 呼び出しは、最上位のサーブレットから呼び出す必要があります。それは、いつインクルードが開始されるのか、およびこのヘッダーが既にフラッシュされているのかどうかを予測できないからです。これに対する例外は、AsyncRequestDispatcherConfig の transferState が有効になっており、insertFragmentBlocking が呼び出される場合です。この場合は通常、ヘッダーを追加すると例外が作成されます。
- フィルター
- インクルードにフィルターが存在している場合は、そのフィルターが非同期スレッドで発行されます。
- ネストされている非同期インクルード
- ネストされている非同期インクルードは、集約を複雑にするため、サポートされていません。ただし、非同期インクルードは、ネストされている同期インクルードを持つことができます。ネストされている非同期インクルードを実行しようとすると、同期インクルードに戻ります。
トランザクション
作業マネージャーにサブミットされるすべてのタスクは、独自のトランザクションを使用して呼び出されます。 これは、一般的なエンタープライズ Bean のコンテナー管理トランザクションと同様です。ランタイムは、メソッドを開始する前にローカル・トランザクションを開始します。 タスクは、タスク独自のグローバル・トランザクションを開始できます (このトランザクションが呼び出し元 Java EE コンポーネントにとって可能である場合)。
タスクが例外を作成すると、すべてのローカル・トランザクションがロールバックされます。 メソッドが正常に戻された場合、完了していないすべてのローカル・トランザクションは、その Bean 用に構成された未解決アクション・ポリシーに従って完了します。 タスクが独自のグローバル・トランザクションを開始してこのグローバル・トランザクションをコミットしない場合、そのトランザクションはメソッドが戻るときにロールバックされます。
接続管理
- JNDI 名がアプリケーション内に、例えばプロパティーまたはストリング・リテラルとしてハードコーディングされている。
- 接続ファクトリーは、共有有効範囲を指定する方法がないため共有されない。
パフォーマンス
インクルードは非同期的に完了するため、ある要求に関する合計パフォーマンス・データでは、非同期インクルードのパフォーマンスを考慮する必要があります。要求の合計時間は、以前は、最上位サーブレットが完了する時間によって理解されましたが、現在はそのサーブレットはインクルードが完了する前に終了します。この場合でも最上位サーブレットは、各インクルードに必要な追加のセットアップ時間の大部分を占めています。
そのため、完全な要求が ARD チャネルを通過する時間を測定するために、新しい ARD パフォーマンス・メトリックが Performance Monitoring Infrastructure に追加されました。これらのメトリックの細分度は、要求 URI レベルです。
ARD は、使用可能にする必要があるオプション機能であるため、ARD を使用していない場合はパフォーマンスの下降は見られません。ただし、ARD 対応アプリケーション・サーバーに常駐する非 ARD アプリケーションは、ARDChannel という余分な層による悪影響を受けます。このチャネル層は、それがどのアプリケーションに行くのかを知らないため、チャネル・チェーン内のすべてのアプリケーションに対してオンまたはオフのいずれかになります。オン/オフは仮想ホストごとに定義されます。
セキュリティー
サーブレット仕様に従い、セキュリティー同期インクルード・ディスパッチではセキュリティーは呼び出されません。ただし、ServletRequest の isUserInRole および getUserPrincipal メソッドのプログラムでの使用をサポートするために、セキュリティー・コンテキストは Concurrency Utilities for Java EE を介して渡されます。このセキュリティー・コンテキストは、Web Services Security を使用するリモート要求ディスパッチにまで伝搬することもできます。