3章 Servletインターフェイス (The Servlet Interface)

 

このServletインターフェイスは、サーブレットのAPIの中心となる抽象メソッドである。総てのサーブレットはこのインターフェイスを直接、あるいは間接的に実装する。Servletを実装したクラスは、GenericServletHttpServletの二つである。もっとも一般的なのは、プログラマは自分のサーブレットを作成するのにHttpServletを拡張する。

 

 

3.1 要求処理メソッド (Request Handling Methods)

 

Servletインターフェイスには、要求処理のためのメソッドとしてserviceメソッドが定義されている。サーブレットコンテナがサーブレットのインスタンスに引き渡す各要求毎にこのメソッドが呼び出される。いつの時点においても、このserviceメソッドのなかでは複数の要求スレッドが実行していても良い。

 

 

3.1.1 HTTP固有の要求処理メソッド (HTTP Specific Request Handling Methods)

 

抽象サブクラスであるHttpServletでは、HTTPベースの要求処理の便をはかってserviceメソッドが自動的に呼び出す幾つかのメソッドが追加されている。即ち:

 

-     HTTP GETを処理するdoGet

-     HTTP POSTを処理するdoPost

-     HTTP PUTを処理するdoPut

-     HTTP DELETEを処理するdoDelete

-     HTTP HEADを処理するdoHead

-     HTTP OPTIONSを処理するdoOptions

-     HTTP TRACEを処理するdoTrace

 

通常HTTPベースのサーブレットを開発する場合は、doGetdoPostの二つのメソッドにのみ集中すれば良いはずである。のこりのメソッドは、HTTPプログラミングに熟知したプログラマのための上級メソッドといえる。

 

doPutdoDeleteは、サーブレット開発者がこれらの機能を持つHTTP/1.1クライアントに対応させる為のものである。HttpServletdoHeadメソッドはdoGetメソッドが実行するものの特殊化したメソッドであるが、クライアントにはdoGetメソッドで作られたヘッダ部分のみを送り返す。DoOptionsメソッドは、どのHTTPメソッドが直接該サーブレットでサポートされているかを知り、この情報をクライアントに返す。doTraceメソッドは、TRACE要求に送られている総てのヘッダを附した応答を発生させる。

 

HTTP/1.0をサポートするコンテナにおいては、HTTP/1.0ではPUTDELETEOPTIONSTRACEなどが定義されていないので、doGetdoHeaddoPost3つのメソッドのみが使用される。

 

 

3.1.2 条件付GETのサポート (Conditional GET Support)

 

条件付GETに対応するために、HttpServletインターフェイスではgetLastModifiedメソッドが定義されている。条件付GET動作とは、コンテント ボディ部分が、指定された時刻移行に変更された場合のみに送信するように指定したヘッダが付加されたHTTP GETメソッドで、クライアントが資源を要求してきた場合のことをいう。

 

DoGetメソッドを実装、要求ごとに必ずしも変化しないようなコンテンツを出すようなサーブレットでは、ネットワーク資源の有効活用のためこのメソッドを実装すべきである。

 

 

3.2 インスタンスの数 (Number of Instances)

 

デフォルトとしては、ひとつのコンテナ内の、サーブレット定義(Servletインターフェイスを実装したクラス名と、それに関連する初期化パラメタ)あたりのサーブレット クラスのインスタンスは唯一つでなければならない。

 

SingleThreadModelインターフェイスを実装したサーブレットの場合は、サーブレットコンテナは該サーブレットのインスタンスを複数インスタンス化し、一方では要求を単一のインスタンスにシリアル化しつつ、大量の要求の重負荷を処理する。

 

組込み記述子(deployment descriptor)distributableとしてマークし、アプリケーションの一部としてサーブレットが導入されたときは、コンテナには、Java仮想マシン(VM)あたりのサーブレット定義あたりのサーブレットクラスのインスタンスはひとつである。もしサーブレットが配布可能なWebアプリケーションであるとともに、SingleThreadModelインターフェイスを実装しているときは、該コンテナの各仮想マシン内では、該コンテナは該サーブレットの複数のインスタンスをインスタンス化させても良い。

 

 

3.2.1 SingleThreadModeに関する注記 (Note about SingleThreadMode)

 

SingleThreadModelインターフェイスを実装すれば、同一時刻においては単一のスレッドが与えられたサーブレットのインスタンスのserviceメソッドを通して実行中であることが保証される。この保証はサーブレットのインスタンスに対してのみ適用されることに注意のこと。HttpSessionのインスタンスの如く、同一時刻において複数のサーブレットのインスタンスにアクセス可能なオブジェクトに対しては、SingleThreadModelを実装したものも含めてどの時刻においても複数のサーブレットがアクセス可能である。

 

 

3.3 サーブレットのライフ サイクル (Servlet Life Cycle)

 

メモリへのロード、インスタンス化と初期化、クライアントからの要求処理、サービスからの除去といった、きちんと定義されたライフ サイクルを通してサーブレットは管理されている。このライフ サイクルはAPIjavax.servlet.Servletインターフェイスにあるinitservice、そしてdestroyメソッドで記述されており、総てのサーブレットが直接的に、あるいはGenericServletまたはHttpServlet抽象クラス経由で間接的に、実装しなければならない。

 

 

3.3.1 ロードとインスタンス化 (Loading and Instantiation)

 

サーブレットのロードとインスタンス化はサーブレット コンテナの責任である。ロードとインスタンス化はエンジンが開始したとき生じさせ得るし、コンテナが要求をサービスするためにそのサーブレットが必要になったと判断するまでこれを保留させることも可能である。

 

最初に、そのサーブレット型のクラスの所在をサーブレット コンテナが把握せねばならない。必要とあらば、サーブレット コンテナはローカルのファイル システム、リモートのファイル システム、あるいは他のネットワーク サービスから通常のJavaクラスロード機能を使ってサーブレットをロードする。

 

コンテナがそのServletクラスをロードしたら、該クラスを使うためにそのクラスのオブジェクト インスタンスにインスタンス化する。

 

あるサーブレット コンテナ内には、与えられたServletクラスの複数のインスタンスが存在し得ることに注意。このことは、例えばある特定のクラスを異なった初期化パラメタで使う、複数のサーブレット定義の場合が該当する。また、サーブレットがSingleThreadModelインターフェイスを実装し、かつコンテナがその複数のインスタンスをプールする場合にも生じ得る。

 

 

3.3.2 初期化 (Initialization)

 

サーブレットのオブジェクトがロードされインスタンス化されたら、クライアントからの要求受付可能となる前に、コンテナはこのサーブレットの初期化をしなければならない。初期化は、サーブレットが継続的に蓄積されているコンフィギュレーション データの読出し、手間のかかるリソースの初期化(たとえばJDBCベースの接続)、あるいはその他の一時的な処理を実行する為に用意されているものである。コンテナは、Servletインターフェイスのinitメソッドを、ServletConfigインターフェイスを実装した特定の(サーブレット定義あたり)オブジェクトを使って呼びだすことでそのサーブレットの初期化をおこなう。このコンフィギュレーションオブジェクトにより、サーブレットはコンテナのコンフィギュレーション情報から名前-値の初期化パラメタをアクセスすることができる。コンフィギュレーションオブジェクトはまた、そのなかでサーブレットが走っているランタイムの環境を記述したServletContextインターフェイスを実装したオブジェクトに、サーブレットがアクセス可能ならしめるものでもある。

 

 

3.3.2.1 初期化におけるエラーの条件 (Error Conditions on Initialization)

 

初期化中、サーブレット インスタンスはUnavailebleExceptionまたはServletExceptionの例外を発生させることでアクティブなサービスの状態に移行できないことを通知できる。この種の例外をサーブレット インスタンスが発生したら、これをサービス可能な状態に持っていってはいけないし、このインスタンスは直ちにコンテナによって開放さればならない。この場合初期化が成功しているとは考えられないので、destroyメソッドは呼ばれない。

 

不成功のサーブレットを開放したら、コンテナはどの時点でも新たなインスタンスをインスタンス化し初期化して良い。この規則の唯一つの例外は、失敗したサーブレットからアベーラブルでない最小時間を示すUnavailableException例外が発生されたときで、このときは、新しいサーブレットのインスタンスの作成と初期化をこの最小時間が経過するまで待たねばならない。

 

 

3.3.2.2 ツールの考察 (Tool Considerations)

 

ツールがウェブ アプリケーションをロードし診断するとき、このアプリケーションのメンバークラスをロードし診断して良い。これがスタティックな初期化メソッドの実行を開始させる。この機能のゆえ、ソフトウエア開発者はServletインターフェイスのinitメソッドが呼ばれていない限り、サーブレットがアクティブなコンテナのランタイム下にあると仮定してはいけない。例えば、そのスタティックな初期化メソッドが実行呼出されたときは、サーブレットはデータベースあるいはエンタープライズ JavaBeansコンポネント アーキテクチャ コンテナとの接続を開始したりしてはならないことを意味する。

 

 

3.3.3 要求の処理 (Request Handling)

 

サーブレットの初期化が無事終了したら、サーブレット コンテナはこれをクライアントからの要求処理のために使用して良い。各要求はServletRequest型の要求オブジェクトとして渡され、これによりサーブレットは用意されたServletResponse型のオブジェクトで応答を作成することができる。これらのオブジェクトはServletインターフェイスのserviceメソッドのパラメタとして渡される。HTTP要求の場合は、コンテナはHttpServiceRequestHttpServiceResponseを実装した要求と応答のオブジェクトをわたさねばならない。

 

サーブレットのインスタンスが作成されサーブレット コンテナにサービス可能な状態におかれても、そのライフタイムにわたって要求を処理しないサーブレットもあることに注意されたい。

 

 

3.3.3.1 マルチスレッドの問題 (Multithreading Issues)

 

クライアントからの要求をサービスしている最中は何時でも、サーブレット コンテナは複数のクライアントからの複数の要求を該サーブレットのserviceメソッドを介して送りこんで良い。このことは、開発者はサーブレットがきちんと並行処理に対応するように注意しなければならないことを意味する。

 

開発者がこのデフォルトの機能を望まないなら、SingleThreadModelインターフェイスを実装したサーブレットをプログラムして良い。このインターフェイスを実装することにより、任意の時間においては唯一つの要求スレッドのみがserviceメソッドを使っていることが保証される。サーブレット コンテナは、あるサーブレットへの要求を直列化するか、あるいはサーブレットのインスタンスをプールすることでこれを保証させる。サーブレットが配布可能(distributable)とマークしたアプリケーションの一部である場合は、コンテナはこのアプリケーションが配布される各VMにサーブレットのインスタンスのプールを保持して良い。

 

開発者がserviceメソッド(あるいはHttpServlet抽象クラスのserviceメソッドから要求及び応答が回送されるdoGetdoPostなどのメソッド)をsynchronizedキーワードで定義した場合には、サーブレットコンテナは実行中のJavaランタイムの必要に応じて要求を直列化する。しかしながら、コンテナはSingleThreadModelを実装したサーブレットに対して行うと同じようにインスタンスのプールを作ってはならない。プログラマがserviceメソッドあるいはdoGetdoPostなどのHttpServletのメソッドにsynchronizedキーワードを使わないことを強く推奨する。

 

 

3.3.3.2 要求処理中の例外 (Exceptions During Request Handling)

 

サーブレットは要求のサービス中にServletExceptionあるいはUnavailableExceptionのいずれかをスローさせて良い。ServletExceptionは、要求の処理中になんらかのエラーが発生し、コンテナはこの要求のクリーンアップの為に適切な処置をとるべきであることを通知するものである。UnavailableExceptionはこの要求をサーブレットは一時的あるいは永久に処理できないことを通知する。

 

UnavailableExceptionにより永久的な非アベーラビリティが通知された場合には、サーブレット コンテナはこのサーブレットをサービスから除去し、そのdestroyメソッドを呼び、このサーブレット インスタンスを除去しなければならない。

 

UnavailableExceptionにより一次的な非アベーラビリティが通知された場合には、コンテナは一時的にアベーラブルでない期間中は要求を回さないように選択できる。この期間は、コンテナは拒絶された要求に対してSERVICE_UNAVAILBLE(503)応答を何時アベーラブルになるかを示すRetry-Afterヘッダを附して返さなければならない。コンテナは一時的と恒久的の区別を無視して、すべてのUnavailableExceptionを恒久的とみなしてこのサーブレットをサービスから外す選択をしてもよい。

 

 

3.3.3.3 スレッド安全性 (Thread Safety)

 

開発者は、要求と応答のオブジェクトの実装はスレッド セーフを保証していないことに注意しなければならない。このことは、これらのオブジェクトは要求処理スレッドのスコープ内でのみしか使ってはならないことを意味する。この要求及び応答オブジェクトへの参照は、結果が不定となるので、他のスレッドで実行中のオブジェクトには許されない。

 

 

3.3.4 サービスの終了 (End of Service)

 

サーブレット コンテナは、何時もサーブレットをロードしたままでいるように要求されているわけではない。サーブレットのインスタンスはサーブレットコンテナにはたったの1ミリ秒、あるいはサーブレットコンテナのライフタイム中(数日、数ヶ月、あるいは数年間)、あるいはその間のどんな期間でもアクティブな状態に維持され得る。

 

サーブレット コンテナがサーブレットをサービスから外さねばならなくなったとき(例えばコンテナがメモリ資源の節約が必要になったり、自分自身がシャットダウン中のとき)、サーブレットに対して各サーブレットが使用中のリソースを開放し、継続的な状態の保管の為の猶予をあたえねばならない。その為に、サーブレット コンテナはServletインターフェイスのdestroyメソッドを呼び出す。

 

サーブレット コンテナがdestroyメソッドを呼べるようになる前に、該サーブレットのserviceメソッドで現在走っているどのスレッドに対してもこれを終了させるか、あるいはサーバが定めたタイムリミットを超過させるかのための余裕をコンテナがdestroyメソッドを呼ぶ前に与えねばならない。

 

ひとたびあるサーブレット インスタンスのdestroyメソッドが呼ばれたら、コンテナは該サーブレットインスタンスあての要求をもはや送りこんではならない。該サーブレットが再び必要になったときは、コンテナはこのサーブレット クラスの新しいインスタンスでこれに対応しなければならない。

 

destroyメソッドが終了したら、サーブレット コンテナはこのサーブレット インスタンスを開放し、ガーベージ コレクションの対象としなければならない。