この章では、サーブレットの主な機能とAPI、JBossでのサーブレットAPIとその標準に対する拡張機能のサポート、およびOC4JでのサーブレットAPIのサポートについて説明します。
サーブレットは、Webコンテナおよびサーブレット・エンジンで実行されるJavaクラスのインスタンスです。サーブレットを使用して、動的なWebページを生成します。サーブレットでは、通常はHTTPプロトコルを使用して、Webクライアントからのリクエストの受信および応答が行われます。
サーブレットには、従来のCGIプログラミングと比較すると次のメリットがあります。
各サーブレットは、別のプロセスでは実行されません。したがって、リクエストごとに新しいプロセスを作成するというオーバーヘッドが解消されます。
サーブレットは、リクエストを終了してから次のリクエストを行うまでの間もメモリーに保持されます。CGIプログラム(および大規模なランタイム・システムまたはインタプリタ)は、CGIのリクエストごとにロードして起動する必要があります。
すべてのリクエストを同時に処理する1つのみのインスタンスが存在します。これによって、メモリーが節約され、永続的なデータをサーブレットで簡単に管理できます。
サーブレットは、(アプレットがWebブラウザのサンドボックス内で実行される方法と同様の方法で)制限付きのサンドボックス内でサーブレット・エンジンによって実行できるため、安全に使用できます。
サーブレットは、スケーラブルであり、複数のアプリケーション・サーバー構成をサポートしています。サーブレットでは、データのキャッシュ、データベースへのアクセス、および他のサーブレット、JSPファイル、(環境によっては)Enterprise JavaBeansなどとのデータの共有も可能です。
サーブレットAPIは、javax.servlet
およびjavax.servlet.http
という2つのJava拡張パッケージで指定されています。ただし、ほとんどのサーブレットでは、サーブレットAPIの標準的な実装であるjavax.servlet.GenericServlet
およびjavax.servlet.http.HttpServlet
のいずれかが拡張されています。これらのうち、javax.servlet
のクラスおよびインタフェースはプロトコルに依存しませんが、javax.servlet.http
にはHTTPに固有のクラスが含まれています。
サーブレットAPIのサポートは、次の4つのカテゴリで提供されています。
サーブレットのライフ・サイクル管理
サーブレット・コンテキストへのアクセス
ユーティリティ・クラス
HTTP固有のサポート・クラス
使用する目的に応じて、サーブレットAPIクラスが識別されます。
目的 | クラスまたはインタフェース |
---|---|
サーブレットの実装 |
|
サーブレットの構成 |
|
サーブレットの例外 |
|
リクエスト/レスポンス |
|
セッション・トラッキング |
|
サーブレット・コンテキスト |
|
サーブレット・コラボレーション |
|
サーブレットは、Webサーバー自体と同じプロセスの一部として、Webサーバー・プラットフォームで実行されます。Webサーバーでは、各サーブレット・インスタンスの初期化、起動、および破棄が行われます。Webサーバーでは、javax.servlet.Servlet
という単純なインタフェースを介してサーブレットとの通信が行われます。
このインタフェースは、次の3つの主要メソッドで構成されています。
init()
service()
destroy()
また、次の2つの補助メソッドも含まれています。
getServletConfig()
getServletInfo()
init()
メソッドサーブレットが初めてロードされると、init()
メソッドが起動され、ファイルのオープン、サーバー接続の確立などの初期プロセスが開始されます。サーブレットは、サーバーに永続的にインストールされた場合、サーバーの起動時にロードされます。
そうでない場合、サーブレットは、サーブレットによって提供されるサービスへの最初のクライアント・リクエストがサーバーで受信されると、サーバーによってアクティブ化されます。init()
メソッドは、service()
メソッドへのコールなどの他のコールがサーブレットに行われる前に終了することが保証されています。init()
メソッドは、1回のみコールされます。サーブレットがサーバーによって再ロードされないかぎり、再度コールはされません。
init()
メソッドは、ServletConfig
オブジェクトへの参照である1つの引数を取ります。このオブジェクトによって、サーブレットに初期化引数が提供されます。このオブジェクトには、サーブレットの環境に関する情報が格納されているServletContext
オブジェクトを戻すgetServletContext()
メソッドが含まれています。
service()
メソッドservice()
メソッドは、サーブレットの中心的な機能です。クライアントからのリクエストごとに、サーブレットのservice()
メソッドが1回コールされます。service()
メソッドでは、次の2つのパラメータを使用して、リクエストの読取りおよびレスポンスの生成が行われます。
クライアントからのデータが含まれているServletRequest
オブジェクト。データは、パラメータの名前/値のペアおよびInputStream
で構成されています。クライアントのパラメータ情報を戻すいくつかのメソッドが提供されています。クライアントのInputStream
は、getInputStream()
メソッドを使用して取得できます。このメソッドによってServletInputStream
が戻されます。これを使用して、クライアントから追加データを取得できます。バイト・レベルではなく文字レベルでデータを処理する必要がある場合は、かわりにgetReader()
を使用してBufferedReader
を取得できます。
クライアントに戻すサーブレットの応答を表すServletResponse
。レスポンスを準備する場合は、まずメソッドsetContentType()
をコールして、応答のMIMEタイプを設定します。次に、getOutputStream()
メソッドを使用してServletOutputStream
取得するか、またはgetWriter()
メソッドを使用してPrintWriter
を取得し、データをクライアントに戻します。
クライアントがサーブレットに情報を送信するには2つの方法があります。1つはパラメータ値を送信する方法で、もう1つはInputStream
(またはReader
)を使用して情報を送信する方法です。パラメータ値は、URLに埋め込むことができます。service()
メソッドのジョブは単純です。このジョブでは、ホスト・サーバーから送信されてくるクライアント・リクエストごとにレスポンスが作成されます。ただし、同時に処理されるサービス・リクエストが複数存在する場合があります。サービス・メソッドでファイル、データベース、外部データなどの外部リソースが必要な場合、リソースへのアクセスは、スレッドセーフにする必要があります。
destroy()
メソッドdestroy()
メソッドをコールすると、サーブレットがアンロードされる前に、サーブレットのすべてのリソース(オープンされているファイル、データベース接続など)をクリーンアップできます。このメソッドは、クリーンアップ操作が不要な場合、空にすることができます。
サーバーは、すべてのサービス・コールが完了するか、または一定の時間が経過するまでdestroy()
メソッドのコールを待機します。つまり、destroy()
メソッドは、実行時間が長いservice()
メソッドの実行中にコールされる可能性があります。destroy()
メソッドは、すべてのservice()
コールが完了するまで必要なリソースがクローズされないように記述する必要があります。
HTTPは、ステートレスなプロトコルであるため、クライアントがリソースをリクエストするたびにサーバーに対して別の接続がオープンされます。また、接続間でコンテキストが保持されないため、各トランザクションは独立したものとなります。ただし、ほとんどのWebアプリケーションはステートレスではありません。堅牢なWebアプリケーションでは、ユーザーと対話し、ユーザーのリクエストの性質を記憶し、あるリクエストでユーザーに関して収集したデータを、同じユーザーからの次回のリクエストで利用できるようにする必要があります。代表的な例には、インターネット商取引でのショッピング・カート・アプリケーションがあります。サーブレットAPIでは、複数の接続にまたがる場合でも、セッションの識別およびセッションへのデータの関連付けのための技術が提供されます。これらの技術には、次のものがあります。
Cookie
URLリライティング
非表示のフォーム・フィールド
(使用されている技術に関係なく)アプリケーション・コード内のセッション情報を手動で管理する必要性をなくすには、JavaサーブレットAPIのHttpSession
クラスを使用します。HttpSession
インタフェースを使用すると、サーブレットで次の処理を実行できます。
セッションに関する情報の表示および管理。
複数のページ・リクエストおよび接続を含めるための複数のユーザー接続にまたがる情報の保持。
Cookieがセッション・トラッキングの最も一般的な方法です。Cookieでは、クライアント・マシン上の人間が判読可能なファイルに、セッションに関する情報が格納されます。後続のセッションでは、Cookieにアクセスして情報を抽出できます。サーバーでは、CookieからのセッションIDがそのセッションのデータに関連付けられます。関連するCookieが複数ある場合、Cookieの有効期限を決定する必要がある場合、および一意のセッション識別子が多数必要な場合、この処理は複雑になります。また、Cookieには、最大サイズが4KB、ドメイン当たりの最大数が20個という制限もあります。Cookieには、ユーザーのプライバシの問題もあります。自身のローカル・ディスクの情報をプログラムによって格納および取得されることを好まず、Cookieを無効にしたり、Cookieを完全に削除するユーザーもいます。したがって、セッション・トラッキングのメカニズムをCookieのみに頼ることはできません。
HttpSession
オブジェクトセッション・データは、収集する方法にかかわらず、格納する場所が必要です。HttpSession
オブジェクトを使用すると、サーブレットのセッション・データを格納し、ユーザーに関連付けることができます。
HttpSession
オブジェクトを使用する場合の基本的な手順は、次のとおりです。
セッション・オブジェクトを取得します。
セッション・オブジェクトに対して読取りまたは書込みを行います。
セッションを強制的に終了するか、または自動的に期限切れさせて終了します。
セッションは、サーブレットに設定されている値に応じて、特定の期間または永続的に持続します。同じクライアントからサーバーへの複数のリクエストの追跡に、一意のセッションIDが使用されます。永続性は、複数のサーブレットが含まれている可能性があるWebアプリケーションのコンテキスト内で有効です。サーブレットでは、別のサーブレットによって保存されているオブジェクトにアクセスできます。オブジェクトは、名前で識別され、セッションにバインドされているとみなされます。これらのオブジェクト(setおよびgetメソッドがこれらに対して実行される場合は属性と呼ばれる)は、リクエスト、セッションまたはアプリケーションの有効範囲内の他のサーブレットで使用できます。
サーブレットは、リクエスト間の状態を維持するために使用しますが、従来のCGIおよび多くのCGIに代わる方法で実装する場合、この操作は煩雑になります。1つのみのサーブレット・インスタンスが作成され、リクエストごとに、サーブレットのサービス・メソッドをコールする新しいスレッドが生成されます(サービス・メソッドによってdoGet
またはdoPost
がコールされます)。このため、共有データは、サーブレットの通常のインスタンス変数(フィールド)に配置する必要のみがあります。したがって、サーブレットでは、ブラウザによるページの再ロード時に実行中の計算に適切にアクセスできます。また、リクエストの結果を新しい順にN個保持できるため、最近行ったリクエストのパラメータと同じパラメータが新しいリクエストで指定された場合、すぐに結果が戻されます。サーブレットにも、作成者は共有データへのマルチスレッド・アクセスを同期させる必要があるという通常のルールが適用されます。
また、サーブレットでは、ServletContext
オブジェクト(getServletContext
メソッドを介して使用可能)に永続的なデータを格納することもできます。ServletContext
にはsetAttribute
およびgetAttribute
メソッドが含まれています。これらのメソッドによって、指定したキーに関連付けられている任意のデータを格納できます。データをインスタンス変数に格納する場合とServletContext
に格納する場合の相違点として、ServletContext
がサーブレット・エンジンまたはWebアプリケーション内のすべてのサーブレットで共有される点があげられます。
サーブレット仕様に定義されているとおり、Webアプリケーションは、サーブレット、JavaServer Pages(JSP)、Javaユーティリティ・クラスとライブラリ、静的ドキュメント(HTMLページ、イメージ、クライアント・サイドのアプレット、Bean、クラスなど)、およびサーブレット対応のすべてのWebサーバーに移植性を保持した状態でデプロイされるようにセットアップされたその他のWebリソースの集合です。Webアプリケーションは、そのまま1つのアーカイブ・ファイルに格納できます。また、そのファイルを特定のディレクトリに配置することによってデプロイできます。
Webアプリケーション・アーカイブ・ファイルの拡張子は.war
です。 WARファイルは、(jar
ユーティリティを使用して作成された).jar
ファイルを別の拡張子で保存したファイルです。JAR形式では、JARファイルを圧縮形式で保存し、そのコンテンツにデジタル署名できます。特定の操作用の.jar
ファイルを区別するために、.jar
ファイル拡張子のかわりに.war
が選択されています。WARファイル・リストの例を次に示します。
index.html howto.jsp feedback.jsp images/banner.gif images/jumping.gif WEB-INF/web.xml WEB-INF/lib/jspbean.jar WEB-INF/classes/MyServlet.class WEB-INF/classes/com/mycorp/frontend/CorpServlet.class WEB-INF/classes/com/mycorp/frontend/SupportClass.class
インストール時に、WARファイルをサーバー上の任意のURI接頭辞パスにマッピングできます。その接頭辞で始まるすべてのリクエストが、このWARファイルで処理されます。たとえば、前述のWARファイルが接頭辞/demo
の下にインストールされた場合、サーバーでは/demo
で始まるすべてのリクエストの処理にこのWARファイルが使用されます。/demo/index.html
に対するリクエストでは、WARファイルのindex.html
ファイルが使用されます。/demo/howto.jsp
または/demo/images/banner.gif
に対するリクエストの場合も、WARファイルのコンテンツが使用されます。
WEB-INF
ディレクトリの概要WEB-INF
ディレクトリは、特殊なディレクトリです。このディレクトリ内のファイルは直接クライアントには提供されません。これらのファイルにはJavaクラスとWebアプリケーションの構成情報が含まれています。 このディレクトリは、JARファイルのMETA-INF
ディレクトリと同様に機能します。このディレクトリには、アーカイブ・コンテンツに関するメタ情報が含まれています。WEB-INF/classes
ディレクトリには、Webアプリケーションのサーブレットおよびサポートするクラスのクラス・ファイルが格納されます。WEB-INF/lib
には、JARファイルに格納されたクラスが含まれています。Webサーバー・クラス・ローダーによって、自動的にWEB-INF/classes
およびWEB-INF/lib
でクラスが検索されます。追加のインストール手順は不要です。
Webアプリケーションのサンプル・リストのWEB-INF
の下にあるサーブレットは、/demo/servlet/MyServlet
、/demo/servlet/com.mycorp.frontend.CorpServlet
などのURIを使用して起動できます。
このアプリケーションへのすべてのリクエストは、サーブレットへのリクエストの場合でも、/demo
で始まることに注意してください。
WEB-INF
ディレクトリ内のweb.xml
ファイルによって、Webアプリケーションの記述子が定義されます。web.xmlファイルには、このファイルが存在しているWebアプリケーションの構成情報が含まれています。web.xmlファイルは、サーブレットの登録、サーブレット初期化パラメータの定義、JSPタグ・ライブラリの登録、セキュリティ制約の定義、他のWebアプリケーション・パラメータの定義に使用されます。
J2EE仕様のサーブレットAPIは、進化し続けています。2年の間にサーブレットAPI 2.0、2.1および2.2が公開されており、このドキュメントを記述している時点での最新バージョンはサーブレットAPI 2.3です。サーブレットの基本アーキテクチャに大きな変更はないため、ほとんどのAPIはそのまま機能します。ただし、強化点および新機能がいくつかあり、一部のAPIは非推奨となりました。
この項では、サーブレットAPI 2.0、2.1、2.2および2.3ドラフト仕様での主な相違点について説明します。
サーブレットAPI 2.1の特徴は、次のとおりです。
リソース(サーブレット)ごとのリクエスト・ディスパッチャ・ラッパー
リクエスト・ディスパッチャは、HTTPリクエストの処理が可能なリソース(サーブレット、JSPなど)およびそのリソースに関連するファイル(静的なHTMLやGIFなど)のラッパーです。サーブレットまたはJSPがインスタンス化されるたびに、サーブレット・エンジンによってリクエスト・ディスパッチャが1つ生成されます。このリクエスト・ディスパッチャがクライアント・リクエストを受信して、リソースにディスパッチします。
アプリケーションごとのサーブレット・コンテキスト
サーブレットAPI 2.0では、サーブレット・エンジンによって、すべてのサーブレットで共有されるサーブレット・コンテキストが1つ生成されました。サーブレットAPI 2.1では、アプリケーションごとに1つのサーブレット・コンテキストが生成されるため、アプリケーションのパーティション化が簡単に行われます。アプリケーション・プログラミング・モデルの説明のとおり、同じ仮想ホスト上のアプリケーションは、互いのサーブレット・コンテキストにアクセスできます。
非推奨のHTTPセッション・コンテキスト
サーブレットAPI 2.0では、HttpSessionContext
インタフェースによって、特定のWebサーバーのすべてのセッションが1つのセッション・コンテキストにグループ化されていました。セッション・コンテキストのインタフェース・メソッドを使用して、サーブレットでセッション・コンテキストのセッションIDリストを取得し、特定のIDに関連付けられたセッションを取得することが可能でした。サーブレットAPI 2.1では、セキュリティ上の安全のため、このインタフェースは非推奨となりました。このインタフェース・メソッドは、NULL
を戻すように再定義されています。
サーブレットAPI 2.2仕様では、「サーブレット・エンジン」という用語が「サーブレット・コンテナ」に変更されました。この変更は、JavaサーブレットAPIがJava 2 Platform Enterprise Edition(J2EE)仕様での必須APIになり、J2EEの用語全体で「コンテナ」が「エンジン」より優先使用されるようになったことを示しています。サーブレットAPI 2.2では、次の新機能が導入されました。
Webアプリケーション(前述のとおり)。
外部データソースへの参照。(JNDIなど)JNDI参照表にリソース(データベース接続など)を追加できます。単純な名前参照を使用して、サーブレットでリソースを指定できます。
アプリケーションのパラメータ情報(アプリケーションの初期化パラメータ)。
サーブレット名の登録。サーブレットを登録し、サーブレットに名前を付ける場所が提供されています。以前は、サーブレットを登録するプロセスがサーバーごとに異なっていたため、デプロイが困難でした。
サーブレット初期化パラメータ。初期化時に、サーブレット・パラメータにパラメータを渡すことができます。これは、以前はサーバー依存のプロセスであった処理を実現するための新しい標準的な方法です。
サーブレットのロード順序。事前ロードするサーブレットおよびそのロード順序を指定します。
セキュリティ制約。保護する必要があるページおよびその保護メカニズムを指定します。フォーム・ベース認証が組み込まれています。
サーブレットAPI 2.3では、サーブレットのコア部分にほとんど変更はありません。追加および変更された内容は、次のとおりです。
JDK 1.2以上が必要です。
フィルタ・メカニズムが作成されています。
アプリケーション・ライフ・サイクル・イベントが追加されています。
国際化サポートがさらに追加されています。
JAR間の依存関係を表現する技術が正式に定義されています。
クラスのロード規則が明確化されています。
エラー属性およびセキュリティ属性が追加されています。
HttpUtilsクラスは非推奨になっています。
DTDの動作の多くが拡張され、明確化されています。
サーブレット2.3 APIの一部として、フィルタリング機能がサポートされています。JBoss 3.2.6では、同様のフィルタリング機能がJBoss固有のパッケージで実現されています。OC4Jでは、Javaサーブレット2.3のフィルタリング仕様がサポートされています。
フィルタリングは、Webサーバーでサーブレットをロードおよび起動する方法の1つです。ローカル・サーブレットとリモート・サーブレットのいずれも、サーブレット・チェーン(後述)の一部にすることができます。ただし、ローカルの内部サーブレットをチェーン化する場合は制約があり、その制約は使用するJ2EEコンテナに固有のものになります。たとえば、JBossでは、内部サーブレットをチェーンで使用する場合、内部サーブレットをチェーンの最初のサーブレットにする必要があります。内部サーブレットには、file
サーブレット、pageCompile
サーブレット、ssInclude
サーブレットおよびtemplate
サーブレットがあります。
一部のリクエストでは、1つのサーブレットのみではなく、順序付けられたサーブレットのチェーンを起動できます。ブラウザからの入力がチェーンの最初のサーブレットに送信され、チェーンの最後のサーブレットからの出力が、ブラウザに返信されるレスポンスになります。チェーン内の各サーブレットによって、直前のサーブレットからの入力が受信され、直後のサーブレットに出力が送信されます。次のものを使用して、受信リクエストに対してサーブレット・チェーンをトリガーすることができます。
リクエストに対するサーブレット・チェーンを示すサーブレットの別名
チェーン内の次のサーブレットをトリガーするMIMEタイプ