サーブレットはどのように機能しますか? インスタンス化、セッション、共有変数、マルチスレッド 質問する

サーブレットはどのように機能しますか? インスタンス化、セッション、共有変数、マルチスレッド 質問する

多数のサーブレットを保持する Web サーバーがあるとします。これらのサーブレット間で情報を渡すために、セッション変数とインスタンス変数を設定しています。

さて、2 人以上のユーザーがこのサーバーにリクエストを送信した場合、セッション変数はどうなるでしょうか? セッション変数は
すべてのユーザーに共通でしょうか、それともユーザーごとに異なるでしょうか?
異なる場合、サーバーはどのようにして異なるユーザーを区別できるのでしょうか?

もう 1 つ似たような質問ですが、特定のサーブレットにアクセスするユーザーがいる場合n、このサーブレットは最初のユーザーが最初にアクセスしたときにのみインスタンス化されますか、それともすべてのユーザーに対して個別にインスタンス化されますか?
つまり、インスタンス変数はどうなりますか?

ベストアンサー1

ServletContext

サーブレットコンテナ(アパッチトムキャット) が起動すると、すべてのウェブアプリケーションがデプロイされ、ロードされます。ウェブアプリケーションがロードされると、サーブレットコンテナは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()メソッドも起動時に呼び出されます。これらのサーブレットは、その値で指定された順序で初期化されます。複数のサーブレットに同じ値が指定されている場合、それらのサーブレットはそれぞれ、、、web.xmlまたはweb-fragment.xmlクラスロードで表示される順序でロードされます@WebServlet。「load-on-startup」値が存在しないか負の場合、init()メソッドは、HTTPリクエストサーブレットに初めてアクセスするinit()メソッドが2つあります。1つはServletConfig引数として、関連する が含まれますServletContext。また、引数を取らない別の は、ServletContext継承されたメソッドによって使用できますgetServletContext()

サーブレットコンテナが上記の初期化手順をすべて完了すると、ServletContextListener#contextInitialized()呼び出されますServletContextEvent引数には、関連する が含まれます。これにより、開発者はプログラムでさらに別のまたは をServletContext登録できるようになりますServletFilterListener

サーブレットコンテナがシャットダウンすると、すべてのウェブアプリケーションがアンロードされ、destroy()初期化されたすべてのサーブレットとフィルタの メソッドが呼び出され、を介して登録されたすべてのServletFilterおよびインスタンスが破棄されます。最後に、ListenerServletContextServletContextListener#contextDestroyed()が呼び出され、ServletContext自体は破棄されます。

HttpServletRequestそしてHttpServletResponse

サーブレットコンテナは、特定のポート番号(開発時にはポート8080、本番時にはポート80が使用されるのが一般的)でHTTPリクエストをリッスンするウェブサーバーに接続されます。クライアント(ウェブブラウザを持つユーザーなど)が、プログラム的に使用URLConnection)がHTTPリクエストを送信すると、サーブレットコンテナは新しいインスタンスを作成します。HttpServletRequestそしてHttpServletResponseFilterそして、それらをチェーン内で定義されているもの、そして最終的にはServletインスタンスに渡します。

の場合フィルターdoFilter()メソッドが呼び出されます。サーブレット コンテナのコー​​ドが を呼び出すとchain.doFilter(request, response)、リクエストとレスポンスは次のフィルタに進むか、フィルタが残っていない場合はサーブレットにヒットします。

の場合サーブレット、メソッドが呼び出されます。デフォルトでは、このメソッドは に基づいてservice()どのメソッドを呼び出すかを決定します。決定されたメソッドがサーブレットに存在しない場合、応答で HTTP 405 エラーが返されます。doXxx()request.getMethod()

リクエストオブジェクトは、HTTPリクエストに関するすべての情報へのアクセスを提供します。メールアドレスヘッダークエリ文字列および本文。レスポンス オブジェクトは、たとえばヘッダーと本文 (通常は JSP ファイルから生成された HTML コンテンツを使用) を設定できるようにすることで、HTTP レスポンスを希望どおりに制御および送信する機能を提供します。HTTP レスポンスがコミットされて終了すると、リクエスト オブジェクトとレスポンス オブジェクトの両方がリサイクルされ、再利用できるようになります。

HttpSession

クライアントが初めてウェブアプリにアクセスしたとき、またはHttpSessionが を介して初めて取得されるとrequest.getSession()、サーブレットコンテナは新しいHttpSessionオブジェクトを作成し、長くてユニークなID( で取得可能session.getId())を生成し、それをサーバーのメモリに格納します。サーブレットコンテナはまた、CookieSet-CookieHTTP 応答のヘッダーに、JSESSIONID名前として 、値として一意のセッション ID が含まれます。

によるとHTTP クッキー仕様(まともなウェブブラウザとウェブサーバーが遵守しなければならない契約)クライアント(ウェブブラウザ)はこれを送信する必要がある。クッキー back in subsequent requests in the Cookie header for as long as the cookie is valid (i.e. the unique ID must refer to an unexpired session and the domain and path are correct). Using your browser's built-in HTTP traffic monitor, you can verify that the cookie is valid (press F12 in Chrome / Edge / Firefox 23+ / IE9+, and check the Net/Network tab). The servlet container will check the Cookie header of every incoming HTTP request for the presence of the cookie with the name JSESSIONID and use its value (the session ID) to get the associated HttpSession from server's memory.

The HttpSession stays alive until it has been idle (i.e. not used in a request) for more than the timeout value specified in <session-timeout>, a setting in web.xml. The default timeout value depends on the servlet container and is usually 30 minutes. So, when the client doesn't visit the web app for longer than the time specified, the servlet container trashes the session. Every subsequent request, even with the cookie specified, will not have access to the same session anymore; the servlet container will create a new session.

On the client side, the session cookie remains as long as the browser instance is running (normally). Unless the browser is configured to restore the last browser session, when the client closes the browser instance (all tabs/windows), the session is lost on the client's side. In a new browser instance, the cookie associated with the session wouldn't exist, so it would no longer be sent. This causes an entirely new HttpSession to be created, with an entirely new session cookie being used.

In a nutshell

  • The ServletContext lives for as long as the web app lives. It is shared among all requests in all sessions.
  • The HttpSession lives for as long as the client is interacting with the web app with the same browser instance, and the session hasn't timed out at the server side. It is shared among all requests in the same session.
  • The HttpServletRequest and HttpServletResponse live from the time the servlet receives an HTTP request from the client, until the complete response (the web page) has arrived. It is not shared elsewhere.
  • All Servlet, Filter and Listener instances live as long as the web app lives. They are shared among all requests in all sessions.
  • Any attribute that is defined in ServletContext, HttpServletRequest and HttpSession will live as long as the object in question lives. The object itself represents the "scope" in bean management frameworks such as JSF, CDI, Spring, etc. Those frameworks store their scoped beans as an attribute of its closest matching scope.

Thread Safety

That said, your major concern is possibly thread safety. これで、サーブレットとフィルターがすべてのリクエスト間で共有されることがわかりました。これが 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.
    } 
}

参照:

おすすめ記事