多数のサーブレットを保持するWebサーバーがあるとします。これらのサーブレット間で情報を受け渡すために、セッション変数とインスタンス変数を設定します。
2人以上のユーザーがこのサーバーにリクエストを送信した場合、セッション変数はどうなりますか?それらはすべてすべてのユーザーに共通のものですか、それともユーザーごとに異なります。それらが異なる場合、サーバーは異なるユーザーをどのように区別することができましたか?
もう1つ類似した質問です。特定のサーブレットにアクセスするn
人のユーザーがいる場合、このサーブレットは最初のユーザーが初めてアクセスしたときにのみインスタンス化されるのですか。つまり、インスタンス変数はどうなりますか。
サーブレットコンテナ( Apache Tomcat など)が起動すると、すべてのWebアプリケーションをデプロイしてロードします。 Webアプリケーションがロードされると、サーブレットコンテナは ServletContext
を1回作成し、サーバーのメモリに保持します。 Webアプリのweb.xml
および含まれるすべてのweb-fragment.xml
ファイルが解析され、見つかった各<servlet>
、<filter>
および<listener>
(またはそれぞれ@WebServlet
、@WebFilter
および@WebListener
の注釈が付いた各クラス)がインスタンス化され、サーバーのメモリに保持されます。インスタンス化されたフィルターごとに、そのinit()
メソッドが新しい FilterConfig
で呼び出されます。
Servlet
の<servlet><load-on-startup>
または@WebServlet(loadOnStartup)
の値が0
より大きい場合、そのinit()
メソッドも起動時に新しい ServletConfig
で呼び出されます。これらのサーブレットは、その値で指定された同じ順序で初期化されます(1
は1番目、2
は2番目など)。複数のサーブレットに同じ値が指定されている場合、それらの各サーブレットは、web.xml
、web-fragment.xml
、または@WebServlet
クラスローディングに現れるのと同じ順序でロードされます。 「load-on-startup」値が存在しない場合、HTTP要求がそのサーブレットに初めてヒットするたびにinit()
メソッドが呼び出されます。
サーブレットコンテナが上記のすべての初期化手順を完了すると、 ServletContextListener#contextInitialized()
が呼び出されます。
サーブレットコンテナがシャットダウンすると、すべてのWebアプリケーションがアンロードされ、初期化されたすべてのサーブレットおよびフィルタのdestroy()
メソッドが呼び出され、すべてのServletContext
、Servlet
、Filter
、およびListener
インスタンスが破棄されます。最後に ServletContextListener#contextDestroyed()
が呼び出されます。
サーブレットコンテナは、特定のポート番号でHTTP要求をリッスンするWebサーバーに接続されます(ポート8080は通常、開発中に使用され、ポート80は運用中に使用されます)。クライアント(Webブラウザーを使用するユーザー、または プログラムでURLConnection
を使用 )がHTTP要求を送信すると、サーブレットコンテナーは新しい HttpServletRequest
と HttpServletResponse
を作成しますオブジェクトを作成し、チェーン内の定義済みのFilter
、および最終的にはServlet
インスタンスに渡します。
filters の場合、doFilter()
メソッドが呼び出されます。サーブレットコンテナのコードがchain.doFilter(request, response)
を呼び出すと、要求と応答は次のフィルターに進むか、フィルターが残っていない場合はサーブレットをヒットします。
servlets の場合、service()
メソッドが呼び出されます。デフォルトでは、このメソッドはdoXxx()
に基づいて呼び出すrequest.getMethod()
メソッドの1つを決定します。決定されたメソッドがサーブレットにない場合、HTTP 405エラーが応答で返されます。
要求オブジェクトは、URL、ヘッダー、クエリ文字列、本文など、HTTP要求に関するすべての情報へのアクセスを提供します。応答オブジェクトは、たとえば、ヘッダーと本文を設定できるようにする(通常、JSPファイルから生成されたHTMLコンテンツを使用する)ことにより、HTTP応答を制御および送信する機能を提供します。 HTTP応答がコミットされて終了すると、要求オブジェクトと応答オブジェクトの両方がリサイクルされ、再利用できるようになります。
クライアントが初めてwebappにアクセスするとき、および/またはrequest.getSession()
を介して HttpSession
を初めて取得するとき、サーブレットコンテナは新しいHttpSession
オブジェクトを作成し、長く一意のIDを生成しますsession.getId()
で取得し、サーバーのメモリに保存します。サーブレットコンテナは、HTTP応答のSet-Cookie
ヘッダーに、名前としてCookie
を、値として一意のセッションIDを指定して JSESSIONID
を設定します。
HTTP Cookie仕様 (適切なWebブラウザーとWebサーバーが遵守する必要がある契約)に従って、クライアント(Webブラウザー)は、Cookie
ヘッダーの後続のリクエストでこのCookieを返送する必要がありますCookieが有効である限り(つまり、一意のIDは有効期限が切れていないセッションを参照している必要があり、ドメインとパスは正しい)。ブラウザーの組み込みHTTPトラフィックモニターを使用して、Cookieが有効であることを確認できます(Chrome/Firefox 23+/IE9 +でF12を押し、Net/Network タブ)。サーブレットコンテナは、Cookie
という名前のCookieが存在するかどうかすべての着信HTTP要求のJSESSIONID
ヘッダーをチェックし、その値(セッションID)を使用して、サーバーのメモリから関連するHttpSession
を取得します。
HttpSession
は、<session-timeout>
の設定であるweb.xml
で指定されたタイムアウト値を超えてアイドル状態になるまで(つまり、リクエストで使用されなくなるまで)存続します。タイムアウト値のデフォルトは30分です。そのため、クライアントが指定された時間を超えてWebアプリにアクセスしない場合、サーブレットコンテナはセッションを破棄します。 Cookieが指定されていても、以降のすべてのリクエストは同じセッションにアクセスできなくなります。サーブレットコンテナは新しいセッションを作成します。
クライアント側では、ブラウザインスタンスが実行されている限り、セッションCookieは存続します。そのため、クライアントがブラウザーインスタンス(すべてのタブ/ウィンドウ)を閉じると、セッションはクライアント側で破棄されます。新しいブラウザインスタンスでは、セッションに関連付けられたCookieは存在しないため、送信されなくなります。これにより、まったく新しいHttpSession
が作成され、まったく新しいセッションCookieが使用されます。
ServletContext
は、Webアプリが存続する限り存続します。これは、allセッションのall要求間で共有されます。HttpSession
は、クライアントが同じブラウザーインスタンスを使用してWebアプリと対話し、サーバー側でセッションがタイムアウトしていない限り存続します。 sameセッション内のall要求間で共有されます。HttpServletRequest
およびHttpServletResponse
は、サーブレットがクライアントからHTTPリクエストを受信してから、完全な応答(Webページ)が到着するまで有効です。他の場所でnot共有されます。Servlet
、Filter
、およびListener
インスタンスは、Webアプリが存続する限り存続します。それらは、allセッションのall要求間で共有されます。attribute
、ServletContext
、およびHttpServletRequest
で定義されているHttpSession
は、問題のオブジェクトが存続する限り存続します。オブジェクト自体は、JSF、CDI、SpringなどのBean管理フレームワークの「スコープ」を表します。これらのフレームワークは、最も近い一致スコープのattribute
としてスコープBeanを格納します。とはいえ、あなたの主な関心事は、おそらくスレッドセーフティです。これで、サーブレットとフィルターがすべてのリクエスト間で共有されていることがわかります。これはJavaのすばらしいところです。マルチスレッドであり、異なるスレッド(HTTP要求)が同じインスタンスを使用できます。それ以外の場合は、すべてのリクエストに対してinit()
およびdestroy()
を再作成するのに費用がかかりすぎます。
また、neverリクエストまたはセッションスコープのデータをinstance変数として割り当てる必要があることも認識してくださいサーブレットまたはフィルター。他のセッションの他のすべてのリクエストで共有されます。それはnotスレッドセーフです!以下の例はこれを示しています。
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.
}
}
つまり、Webサーバーはfirst訪問時に各訪問者に一意の識別子を発行します。次回訪問者が認識されるためには、訪問者はそのIDを返さなければなりません。この識別子によって、サーバーはあるセッションが所有するオブジェクトを別のセッションのものと正しく区別することもできます。
起動時のロード が false の場合
起動時ロード が true の場合
彼がサービスモードとグルーブに着くと、sameサーブレットは他のすべてのクライアントからのリクエストを処理します。
クライアントごとに1つのインスタンスを持つのが良い考えではないのはなぜですか?これについて考える:あなたは来たすべての注文のために1人のピザ屋を雇うのだろうか?それをすればあなたはすぐに廃業するでしょう。
それは少しリスクが伴います。覚えておいてください:この一人の男は自分のポケットの中にすべての注文情報を持っています:あなたが サーブレット上のスレッドの安全性に注意していないのなら 。
Javaサーブレットのセッションは、PHPなどの他の言語のセッションと同じです。ユーザーに固有です。サーバーは、Cookie、URL書き換えなど、さまざまな方法で追跡できます。この Java doc の記事では、Javaサーブレットのコンテキストで説明し、セッションの正確な方法を示しています。維持されるのは、サーバーの設計者に残された実装の詳細です。この仕様では、サーバーへの複数の接続にわたってユーザーに固有のものとして維持する必要があることのみを規定しています。両方の質問の詳細については、 Oracleのこの記事 をご覧ください。
Editサーブレット内部でセッションを操作する方法に関する優れたチュートリアル ここ があります。 here は、Javaサーブレット、その概要、および使用方法に関するSunの章です。これら2つの記事の間に、すべての質問に答えることができるはずです。
サーブレットコンテナ(Apache Tomcatなど)が起動すると、何か問題が発生したりコンテナサイドのコンソールにエラーが表示されたりすると、web.xmlファイルから(アプリケーションごとに1つだけ)読み込まれます。 web.xmlを使用してアプリケーションを展開する(デプロイメント記述子と呼ばれる)。
サーブレットのインスタンス化フェーズでは、サーブレットインスタンスは準備ができていますが、2つの情報が欠落しているため、クライアント要求を処理できません。
1:コンテキスト情報
2:初期設定情報
サーブレットエンジンは、上記の不足している情報をカプセル化したservletConfigインタフェースオブジェクトを作成します。サーブレットエンジンは、servletConfigオブジェクト参照を引数として指定することによって、サーブレットのinit()を呼び出します。 init()が完全に実行されると、サーブレットはクライアントの要求を処理する準備が整います。
A)1回だけ(すべてのクライアント要求に対して新しいスレッドが作成される)、サーブレットの1つのインスタンスだけが、任意の数のクライアント要求を処理します。つまり、1つのクライアント要求サーバーを処理した後は死にません。他のクライアントの要求を待ちます。つまり、サーブレットを使って(内部的にサーブレットエンジンがスレッドを作成する)どのCGI(すべてのクライアント要求に対して)の制限が克服されるのか。
A)getSession()がHttpServletRequestオブジェクトで呼び出されるたびに
ステップ1 :リクエストオブジェクトは着信セッションIDについて評価されます。
ステップ2 :IDが利用できない場合は、まったく新しいHttpSessionオブジェクトが作成され、対応するセッションIDが(つまりHashTableの)生成されます。セッションIDはhttpservletレスポンスオブジェクトに格納され、HttpSessionオブジェクトの参照はサーブレットに返されます。 doGet/doPost).
ステップ3 :ID利用可能な真新しいセッションオブジェクトが作成されていない場合、セッションIDをキーとしてセッションのコレクション内で検索が行われ、リクエストオブジェクトから検索されます。
検索が成功すると、セッションIDがHttpServletResponseに格納され、既存のセッションオブジェクト参照がUserDefineservletのdoGet()またはdoPost()に返されます。
1)サーブレットコードからクライアントに制御が移るとき、セッションオブジェクトがサーブレットコンテナ、すなわちサーブレットエンジンによって保持されていることを忘れないでください。
2)マルチスレッドは、サーブレット開発者が実装するために残しています。つまり、クライアントからの複数の要求を処理しても、マルチスレッドコードに煩わされることはありません。
サーブレットは、アプリケーションの起動時(サーブレットコンテナにデプロイされているとき)、またはサーブレットのインスタンス化時に最初にアクセスされたとき(起動時の設定に応じて)に作成され、サーブレットのinit()メソッドが呼び出されます。その後、サーブレット(その唯一のインスタンス)がすべての要求を処理します(そのservice()メソッドは複数のスレッドによって呼び出されます)。そのため同期をとることはお勧めできません。アプリケーションがアンデプロイされた(サーブレットコンテナが停止した)ときは、destroy()メソッドが呼び出されるので、サーブレットのインスタンス変数を避ける必要があります。
セッション - クリストンプソンが言ったこと。
インスタンス化 - コンテナがサーブレットにマップされた最初のリクエストを受け取ると、サーブレットはインスタンス化されます(起動時に<load-on-startup>
のweb.xml
要素を使用してロードするようにサーブレットが設定されている場合を除く)。同じインスタンスが後続の要求を処理するために使用されます。
サーブレット仕様 JSR-315 は、サービス(およびdoGet、doPost、doPutなど)メソッドにおけるWebコンテナの振る舞いを明確に定義しています(2.3.3.1マルチスレッドの問題、9ページ)。
サーブレットコンテナは、サーブレットのサービスメソッドを通じて同時リクエストを送信することができます。リクエストを処理するために、サーブレット開発者はサービスメソッド内の複数のスレッドとの同時処理に対して適切な準備をしなければなりません。
推奨されていませんが、開発者にとっての代替案は、サービスメソッドに一度に1つのリクエストスレッドしかないことをコンテナに保証するように要求するSingleThreadModelインターフェースを実装することです。サーブレットコンテナは、サーブレット上の要求をシリアル化することによって、またはサーブレットインスタンスのプールを維持することによって、この要件を満たすことができます。サーブレットが配布可能としてマークされているWebアプリケーションの一部である場合、コンテナはアプリケーションが配布されている各JVMにサーブレットインスタンスのプールを保持することがあります。
SingleThreadModelインタフェースを実装していないサーブレットの場合、サービスメソッド(またはHttpServlet抽象クラスのサービスメソッドにディスパッチされるdoGetやdoPostなどのメソッド)がsynchronizedキーワードで定義されている場合、サーブレットコンテナはインスタンスプールアプローチを使用できません。しかし、それを通して要求を直列化しなければなりません。パフォーマンスへの悪影響のため、開発者はこれらの状況でサービスメソッド(またはそれにディスパッチされたメソッド)を同期しないことを強くお勧めします。
上記の説明から明らかなように、 SingleThreadModelサーブレットは、サーブレットコンテナによってスレッドセーフになります。コンテナ実装はこれを2つの方法で行うことができます。
1)単一インスタンスへの要求の直列化(キューイング) - これは、service/doXXXメソッドを同期化するSingleThreadModel BUTを実装していないサーブレットに似ています。または
2)インスタンスのプールを作成する - これは、サーブレットをホストする環境の制限的なパラメータ(メモリ/ CPU時間)に対する、より良いオプションであり、サーブレットの起動/初期化の努力/時間の間のトレードオフです。