[解決済み】サーブレットはどのように動作するのですか?インスタンス化、セッション、共有変数とマルチスレッド
質問
多数のサーブレットを保持するウェブサーバーがあるとします。これらのサーブレット間で情報をやり取りするために、セッション変数とインスタンス変数を設定しています。
ここで、2人以上のユーザーがこのサーバーにリクエストを送信した場合、セッション変数はどうなるでしょうか?
すべてのユーザーで共通なのか、それともユーザーごとに異なるのか?
もし、異なるのであれば、サーバーはどのようにしてユーザーを区別していたのでしょうか?
もう一つ似たような質問ですが、もし
n
が特定のサーブレットにアクセスした場合、このサーブレットは最初のユーザーがアクセスしたときのみインスタンス化されるのでしょうか、それともすべてのユーザーに対して別々にインスタンス化されるのでしょうか?
言い換えれば、インスタンス変数はどうなるのでしょうか?
どのように解決するのか?
ServletContext
サーブレットコンテナ(のようなもの)の場合
Apache Tomcat
) が起動すると、そのすべてのウェブアプリケーションをデプロイして読み込みます。ウェブアプリケーションがロードされると、サーブレットコンテナはそのアプリケーションのための
ServletContext
一度だけ、サーバーのメモリに保存します。ウェブアプリの
web.xml
と、それに含まれるすべての
web-fragment.xml
ファイルが解析され、それぞれの
<servlet>
,
<filter>
と
<listener>
でアノテーションされた各クラスが見つかりました(または
@WebServlet
,
@WebFilter
と
@WebListener
それぞれ) は一度だけインスタンス化され、サーバのメモリにも保持されます。
ServletContext
. インスタンス化された各フィルタに対して、その
init()
メソッドが呼び出され、新しい
FilterConfig
の引数を取り、その引数に関係する
ServletContext
.
を指定した場合
Servlet
には
<servlet><load-on-startup>
または
@WebServlet(loadOnStartup)
よりも大きい値
0
であれば、その
init()
メソッドも起動時に起動され、新しい
ServletConfig
の引数を取り、その引数に関係する
ServletContext
. それらのサーブレットは、その値で指定されたのと同じ順序で初期化されます (
1
が1番目です。
2
は2番目、など)。複数のサーブレットに同じ値が指定された場合、それらのサーブレットはそれぞれ
web.xml
,
web-fragment.xml
または
@WebServlet
クラスローディングを行います。もし、quot;load-on-startup" の値がない場合は
init()
メソッドが呼び出されます。
HTTPリクエスト
はそのサーブレットに初めてヒットします。
サーブレットコンテナが上記の初期化ステップをすべて終了すると、次に
ServletContextListener#contextInitialized()
が呼び出されます。
ServletContextEvent
の引数を取り、その引数には関係する
ServletContext
. これによって、開発者はプログラム上でさらに別の
Servlet
,
Filter
または
Listener
.
サーブレットコンテナがシャットダウンするとき、すべてのウェブアプリケーションをアンロードして、そのアプリケーションを起動します。
destroy()
メソッド、すべての初期化されたサーブレットとフィルタ、そしてすべての
Servlet
,
Filter
と
Listener
インスタンスを登録します。
ServletContext
はゴミ箱に捨てられます。最後に
ServletContextListener#contextDestroyed()
が呼び出され
ServletContext
はゴミ箱に捨てられます。
HttpServletRequest
と
HttpServletResponse
サーブレットコンテナは、特定のポート番号でHTTPリクエストをリッスンするWebサーバーに接続されています(通常、開発時には8080番ポート、本番時には80番ポートが使用されます)。クライアント (例えばウェブブラウザを持つユーザ、あるいは
を使用してプログラム的に
URLConnection
) が HTTP リクエストを送ると、サーブレットコンテナは新しい
HttpServletRequest
と
HttpServletResponse
オブジェクトを作成し、定義された任意の
Filter
が連鎖し、最終的には
Servlet
インスタンスを作成します。
の場合は
フィルター
を使用する場合、その
doFilter()
メソッドが呼び出されます。サーブレットコンテナのコードが
chain.doFilter(request, response)
の場合、リクエストとレスポンスは次のフィルターに進み、 フィルターが残っていない場合はサーブレットにぶつかります。
の場合
サーブレット
を指定すると
service()
メソッドが呼び出されます。デフォルトでは、このメソッドは
doXxx()
に基づいて呼び出されるメソッドです。
request.getMethod()
. 決定されたメソッドがサーブレットに存在しない場合、HTTP 405エラーがレスポンスとして返されます。
リクエストオブジェクトは、HTTPリクエストに関するすべての情報へのアクセスを提供します。 URL , ヘッダー , クエリ文字列 およびボディを含む。レスポンスオブジェクトは、例えばヘッダやボディ (通常は JSP ファイルから生成された HTML コンテンツ) を設定することによって、HTTP レスポンスを思い通りに制御し送信する機能を提供します。HTTP レスポンスがコミットされて終了すると、リクエストオブジェクトとレスポンスオブジェクトの両方がリサイクルされ、再利用できるようになります。
HttpSession
クライアントが初めてウェブアプリケーションにアクセスしたとき、および/または
HttpSession
を経由して初めて取得されます。
request.getSession()
の場合、サーブレットコンテナは新しい
HttpSession
オブジェクトを生成し、長くてユニークな ID (これは
session.getId()
) を作成し、サーバーのメモリに保存します。また、サーブレットコンテナは
Cookie
の中にある
Set-Cookie
ヘッダを持つ HTTP レスポンスの
JSESSIONID
を名前に、その値として一意のセッションIDを指定します。
のように
HTTP クッキー仕様
(まともなウェブブラウザとウェブサーバが遵守すべき契約)、クライアント(ウェブブラウザ)は、この
クッキー
を返し、それ以降のリクエストでは
Cookie
ヘッダは、そのクッキーが有効である限り(すなわち、一意の ID が期限切れのないセッションを参照し、ドメインとパスが正しいこと)、有効です。ブラウザに組み込まれたHTTPトラフィックモニタを使って、クッキーが有効であることを確認できます(Chrome / Firefox 23+ / IE9+でF12キーを押し、そのヘッダをチェックします)。
ネット/ネットワーク
タブをクリックします)。サーブレットコンテナは
Cookie
という名前のクッキーの存在を確認するために、すべての受信 HTTP リクエストの
JSESSIONID
を取得し、その値(セッションID)を使って、関連する
HttpSession
をサーバーのメモリから取得します。
は
HttpSession
で指定されたタイムアウト値以上アイドル (つまり、リクエストで使われない) になるまで、生き続けます。
<session-timeout>
での設定は
web.xml
. タイムアウト値のデフォルトは30分です。そのため、クライアントが指定された時間以上ウェブアプリにアクセスしない場合、サーブレットコンテナは
セッション
. それ以降のすべてのリクエストは、たとえクッキーが指定されていたとしても、同じセッションにアクセスすることはできなくなり、サーブレットコンテナは新しいセッションを作成します。
クライアント側では、ブラウザのインスタンスが動作している限り、セッションクッキーは生き続けます。したがって、クライアントがブラウザのインスタンス(すべてのタブ/ウィンドウ)を閉じると、クライアント側ではセッションがゴミ箱に捨てられます。新しいブラウザのインスタンスでは、セッションに関連するクッキーは存在しないので、もはや送信されないでしょう。このため、まったく新しい
HttpSession
が作成され、全く新しいセッションクッキーが使用されます。
簡単に説明すると
-
は
ServletContext
は、ウェブアプリが生きている限り存続します。の間で共有されます。 すべて のリクエストを すべて セッションで使用されます。 -
は
HttpSession
は、クライアントが同じブラウザインスタンスでウェブアプリとやりとりしていて、サーバー側でセッションがタイムアウトしていない限り、存続します。このセッションは すべて のリクエストは 同じ セッションで使用されます。 -
は
HttpServletRequest
とHttpServletResponse
サーブレットがクライアントからHTTPリクエストを受け取ってから、完全なレスポンス(Webページ)が到着するまでの間、生きています。それは ではない は他の場所で共有されます。 -
すべて
Servlet
,Filter
とListener
インスタンスは、ウェブアプリが存続する限り存続します。これらのインスタンスは すべて のリクエストを すべて セッションで使用されます。 -
任意の
attribute
で定義されているものはServletContext
,HttpServletRequest
とHttpSession
は、当該オブジェクトが生きている限り生き続ける。オブジェクト自体は、JSF、CDI、Springなどのビーン管理フレームワークにおいて、"scope"を表します。それらのフレームワークは、スコープされたビーンをattribute
の、最も近いスコープにマッチする。
スレッドの安全性
とはいえ、あなたの大きな関心事は、もしかしたら
スレッドセーフ
. サーブレットとフィルタはすべてのリクエストで共有されることがおわかりいただけたかと思います。これがJavaの良いところです。Javaはマルチスレッドで、異なるスレッド(HTTPリクエストと読みます)が同じインスタンスを利用することができるのです。そうでなければ、再作成するにはあまりにもコストがかかりすぎます。
init()
と
destroy()
を、すべてのリクエストに適用します。
また、次のことを認識する必要があります。 決して リクエストまたはセッションスコープのデータを インスタンス 変数を使用します。それは他のセッションの他のすべてのリクエストの間で共有されます。それは ではなく スレッドセーフ 以下の例では、このことを説明しています。
public class ExampleServlet extends HttpServlet {
private Object thisIsNOTThreadSafe;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object thisIsThreadSafe;
thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
}
}
こちらもご覧ください。
関連
-
[解決済み] トークンのシンタックスエラー、これらのトークンを削除してください [closed].
-
[解決済み] java.lang.ClassCastException: java.util.Arrays$ArrayList は java.util.ArrayList にキャストできません。
-
[解決済み] 型の不一致:ArrayListからListへの変換ができない
-
[解決済み] java.lang.ClassCastException: java.lang.Long を java.lang.Integer にキャストできない(java 1.6
-
[解決済み] Javaで配列を宣言し、初期化する方法は?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] java.net.URLConnectionを使用してHTTPリクエストを発生させ処理する方法
-
[解決済み] Javaの「for each」ループはどのように機能するのですか?
-
[解決済み] ファイルを作成し、書き込むにはどうすればよいですか?
-
[解決済み] サーブレットとAjaxはどのように使い分ければよいのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Javaで拡張子なしのファイル名を取得する方法は?
-
[解決済み] 警告: コンテキスト初期化中に例外が発生 - 更新の試みはキャンセルされました。
-
[解決済み] Javaでのスキャナが動作しない
-
[解決済み] JOGLまたはLWJGLの既成のプロジェクト
-
[解決済み] mavenのコンパイルに失敗するのはなぜですか?
-
[解決済み] java.lang.ClassNotFoundException: クラス com.ibm.db2.jcc.DB2Driver が Worklight プラットフォームまたはプロジェクトに見つかりませんでした。
-
[解決済み] Java の文字列インデックスが範囲外です。0 [閉店]
-
[解決済み] スリーピング中のスレッドが割り込まれ、データベースへの接続が失われる
-
[解決済み] 文字列の長さに応じて文字列をトリミングする
-
[解決済み] java.sql.SQLRecoverableException: IO エラーです。NL Exceptionが発生しました