2007 年 2 月 28 日 1 時 49 分

データの格納先と寿命(スコープ)


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


Servlet に限らないが、プログラムが使う永続的なデータは、
データベースやファイル等に格納する。

また、プログラムが扱うデータには一時的なものもある。
これは例えば画面のレイアウトや状態管理のために、
(変数などの)メモリを割り当てて格納しておくデータだ。

さて、Web アプリケーションの場合はどうなるか。

永続的なデータに関しては、上記同様に、
データベースやファイル等に格納すればいいのだが、
一時的なデータを格納するためには、
Servlet API で決められたルールに従わなければならない。
それは Servlet が Servlet コンテナの制御下にあるからだ。

Servlet API では開発者の利便性を考えて、
データを格納するための領域をいくつか用意している。

・javax.servlet.http.HttpServletRequest
・javax.servlet.http.HttpSession
・javax.servlet.ServletContext

上記 3 つのクラスについては、その役割を解説してきたが、
これらクラスは、一時的なデータを保持する役割も持つ。

これらクラスはそれぞれ個別に「属性領域」を持っている。
属性領域とは HashMap のようなものであり、
そこに、文字列のキーを利用して
任意のオブジェクトを登録することができる。

属性へのアクセスには、getAttribute, setAttribute,
removeAttribute, getAttributeNames 等のメソッドを利用する。

さて、上記 3 つのクラスはそれぞれに寿命があり、
関連付けられた属性の寿命もそれに従うことになっている。

・HttpServletRequest(リクエストスコープ)

HttpServletRequest の属性は「リクエスト属性」と呼び、
1 つの HTTP 要求の間のみ存在する。
この事を「リクエストスコープを持つ」と呼ぶ。

リクエスト属性は、複数の Servlet が連動する環境で使う。
1 つの Servlet だけで完結するならばあまり使われない。

Web アプリケーションが HTTP 要求を受け取ると、
関連付けられた Servlet に処理を委任するのだが、
その Servlet が前処理を行った後、
別の Servlet を呼び出すような仕組みの場合、
前処理の結果を後の Servlet に渡すために利用する。

最後の Servlet が処理を終わらせて、
利用者に HTTP 応答が返されると、
リクエスト属性は全て破棄される。

HttpServletRequest 自体はスレッドセーフでないが、
HttpServletRequest は、Servlet のメソッドに渡され、
同時に必ず 1 つのスレッド上で実行されるので。
事実上、リクエスト属性のスレッド同期は考えなくてよい。

・HttpSession(セッションスコープ)

HttpSession の属性は「セッション属性」と呼び、
昨日説明したセッションが存在する間有効となる。
この事を「セッションスコープを持つ」と呼ぶ。

セッションは、同一クライアントの要求で共有されるため、
ユーザ ID 等のログイン情報や、
処理状態などを記憶するために使用する事が多い。

セッションは非常に便利なのだが、幾つかの注意点がある。

まず、利用者が多いとセッションが数多く作成されるため、
巨大なメモリを消費するオブジェクトを配置してはならない。

また、クラスタリングを利用する場合、
セッション属性の値は他のクラスタに送信されるので、
格納するオブジェクトはシリアル化可能でなければならない。
(つまり、Serializable を実装しなければならない)

そして、セッションはタイムアウトによって
開発者が予期することなく破棄される事があること。
例えば、FileStream や Connection など、
サーバのリソースを消費するオブジェクトを登録する場合、
そのリソースを解放するタイミングに注意する必要がある。

最後に、クライアントによって、同じタイミングに、
複数の異なるリクエストが要求される可能性があること。

セッションが同一利用者の要求で共有されるということは、
ユーザが、複数のウィンドウを開いたり、
Ajax などによって非同期に処理を行った場合、
クライアントは同時に複数の HTTP 要求を発行する。
これは、素早くフォームの再送信を行っただけでも発生する。

各 HTTP 要求は別のスレッドで処理される可能性があるため、
HttpSession へのアクセスはスレッドセーフではない。
これが意外に盲点になることが多い。

・ServletContext(アプリケーションスコープ)

ServletContext の属性は「アプリケーション属性」と呼び、
Web アプリケーションが実行されている間存在する。
この事を「アプリケーションスコープを持つ」と呼ぶ。

アプリケーション属性は、言わばグローバル変数である。
ServletContext のインスタンスは 1 つだけ存在し、
Web アプリケーションのあらゆる部分で共有される。

ServletContext のアクセスもセッション同様、
スレッドセーフではないということに注意すること。

そのため、通常は Web アプリケーション起動時に、
各種(スレッドセーフの)オブジェクトを登録しておき、
実行中は、読み取り専用として利用する事が多い。

Servlet には、初期化と終了用の専用メソッドがあるため、
ServletContext には、データベース接続など、
リソースを消費するオブジェクトを配置するのも良い方法だ。

以上の事は、Web アプリケーションを開発する上で、
非常に重要なことであるため、必ず習得しておきたい所だ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.