サーブレット&JSPの基本|initとdestroyの基本

サーブレットは1回作られて何度も使われる。initとdestroyで、開始時の準備と終了時の後片付けを理解しよう

これまでサーブレットでは、主にdoGetメソッドやdoPostメソッドを使ってきました。

ブラウザからGETリクエストが送られたときはdoGetメソッド、POSTリクエストが送られたときはdoPostメソッドが実行されます。この2つは、ServletとJSPの学習ではとてもよく登場する基本メソッドです。

しかし、サーブレットクラスには、doGetやdoPost以外にも重要なメソッドがあります。

その代表が、initメソッドとdestroyメソッドです。

initメソッドは、サーブレットのインスタンスが作成された直後に実行されるメソッドです。最初に一度だけ行いたい準備処理を書くときに使います。

destroyメソッドは、サーブレットのインスタンスが破棄される直前に実行されるメソッドです。最後に一度だけ行いたい後片付けを書くときに使います。

この記事では、まずサーブレットクラスがどのようにインスタンス化され、どのタイミングで再利用されるのかを確認します。そのうえで、initメソッドとdestroyメソッドの役割、動作確認の方法、使うときの注意点を学んでいきます。

サーブレットクラスはそのままでは実行できない

これまで、サーブレットクラスを実行する、という表現を使ってきました。

ただし、Javaのしくみとしては、クラスそのものをそのまま実行しているわけではありません。

doGetやdoPostはstaticが付いていないインスタンスメソッドです。そのため、実行するには、そのクラスからインスタンスを作成する必要があります。

通常のJavaクラスであれば、開発者がnewを使ってインスタンスを作成します。

たとえば、普通のクラスなら次のようなイメージです。

種類インスタンス化する人
通常のJavaクラス開発者がnewを使って作成する
サーブレットクラスサーブレットコンテナが自動で作成する

サーブレットクラスの場合、開発者が自分でnewしてインスタンスを作成する必要はありません。

ブラウザからリクエストが届いたとき、アプリケーションサーバ内のサーブレットコンテナが、必要に応じてサーブレットクラスをインスタンス化してくれます。

サーブレットコンテナがインスタンス化してくれる

サーブレットクラスは、Tomcatのようなアプリケーションサーバ上で動作します。

その中で、サーブレットの生成や実行、破棄などを管理している仕組みがサーブレットコンテナです。

開発者は、サーブレットクラスを作成し、URLパターンを指定します。

その後、ブラウザからそのURLへリクエストが送られると、サーブレットコンテナが対象のサーブレットクラスを探し、インスタンス化し、doGetやdoPostを呼び出します。

サーブレット実行までの大まかな流れ

順番内容
1ブラウザからサーブレットのURLへリクエストを送る
2サーブレットコンテナが対象のサーブレットクラスを確認する
3必要に応じてサーブレットクラスをインスタンス化する
4リクエスト方法に応じてdoGetまたはdoPostを呼び出す
5サーブレットがレスポンスを作成してブラウザへ返す

このように、サーブレットのインスタンス化は、開発者が明示的に行うのではなく、サーブレットコンテナが自動で行います。

リクエストのたびにインスタンス化されるわけではない

ここで注意したいのは、サーブレットクラスがリクエストのたびに毎回インスタンス化されるわけではない、という点です。

アプリケーションサーバにとって、インスタンスの生成と破棄は負荷のかかる処理です。

もし、リクエストが届くたびにサーブレットのインスタンスを作成し、レスポンス後に毎回破棄していたら、アクセスが増えたときにサーバへの負荷が大きくなります。

そこで、サーブレットコンテナは、一度作成したサーブレットインスタンスをすぐには破棄しません。

初回リクエスト時にサーブレットインスタンスを作成し、その後のリクエストでも同じインスタンスを再利用します。

サーブレットインスタンスの基本

タイミング動作
初回リクエスト時サーブレットクラスがインスタンス化される
2回目以降のリクエスト時作成済みのインスタンスが再利用される
Webアプリケーション終了時インスタンスが破棄される

このしくみにより、サーバは効率よくリクエストを処理できます。

図1:サーブレットクラスのインスタンス化と再利用

この図から分かること

サーブレットクラスは、初回リクエスト時にサーブレットコンテナによってインスタンス化されます。

一度作成されたインスタンスは、リクエストが終わったあともすぐには破棄されません。2回目以降のリクエストでは、作成済みのインスタンスが再利用されます。

このしくみにより、リクエストのたびにインスタンスを作成する負荷を減らし、効率よく処理できます。

インスタンスは、Webアプリケーションが終了するときなどに破棄されます。

JSPファイルも内部ではインスタンス化される

JSPファイルも、実行されるときには内部でサーブレットとして扱われます。

JSPファイルに初めてリクエストが届くと、まずJSPファイルがサーブレットクラスに変換されます。そのあと、変換されたサーブレットクラスがコンパイルされ、インスタンス化されます。

そのため、JSPファイルへの初回アクセスは、少し時間がかかる場合があります。

JSP実行時の流れ

順番内容
1JSPファイルに初回リクエストが届く
2JSPファイルがサーブレットクラスに変換される
3変換されたサーブレットクラスがコンパイルされる
4インスタンス化される
5HTMLが生成され、ブラウザへ返される

生成されたインスタンスは、Webアプリケーションが終了するまで、またはJSPファイルが更新されるまで再利用されます。

つまり、JSPもサーブレットと同じように、毎回ゼロから作り直されるわけではありません。

initメソッドとdestroyメソッドとは

サーブレットクラスは、HttpServletを継承して作成します。

HttpServletには、doGetやdoPostのほかに、initメソッドとdestroyメソッドも用意されています。

これらは、開発者が直接呼び出すメソッドではありません。

決まったタイミングで、サーブレットコンテナが自動的に呼び出します。

initとdestroyの役割

メソッド呼び出されるタイミング主な役割
initサーブレットインスタンスが作成された直後初期化処理を行う
destroyサーブレットインスタンスが破棄される直前後片付け処理を行う

initメソッドは、最初に一度だけ行いたい準備処理に向いています。

destroyメソッドは、最後に一度だけ行いたい後片付けに向いています。

initメソッドが実行されるタイミング

initメソッドは、サーブレットクラスのインスタンスが作成された直後に実行されます。

多くの場合、対象のサーブレットに初めてリクエストが届いたタイミングで、次のように処理が進みます。

初回リクエスト時の流れ

順番内容
1ブラウザから初回リクエストが届く
2サーブレットコンテナがサーブレットをインスタンス化する
3initメソッドが実行される
4doGetまたはdoPostが実行される
5レスポンスがブラウザへ返される

initメソッドは、インスタンス作成後に一度だけ実行されます。

そのため、リクエストのたびに毎回実行されるわけではありません。

destroyメソッドが実行されるタイミング

destroyメソッドは、サーブレットインスタンスが破棄される直前に実行されます。

たとえば、サーバを停止したとき、Webアプリケーションが終了したとき、再読み込みによって古いインスタンスが破棄されるときなどです。

Webアプリケーション終了時の流れ

順番内容
1Webアプリケーションが終了する
2サーブレットコンテナがサーブレットインスタンスの破棄を準備する
3destroyメソッドが実行される
4サーブレットインスタンスが破棄される

destroyメソッドも、通常のリクエストごとに実行されるわけではありません。

サーブレットインスタンスが終わる直前に、一度だけ実行されます。

図2:initメソッドとdestroyメソッドの実行タイミング

この図から分かること

initメソッドは、サーブレットインスタンスが作成された直後に実行されます。

そのあと、リクエストに応じてdoGetやdoPostが実行されます。

destroyメソッドは、サーブレットインスタンスが破棄される直前に実行されます。

initは最初に一度だけ、destroyは最後に一度だけ実行される、という流れを押さえておくと理解しやすくなります。

initメソッドをオーバーライドする

initメソッドは、HttpServletから継承しているメソッドです。

サブクラスでオーバーライドすると、サーブレットインスタンス作成直後に行いたい処理を書けます。

基本形は次のようになります。

public void init(ServletConfig config) throws ServletException {
    super.init(config);

    // 最初の1回だけ実行したい処理を書く
}

この形で大切なのは、super.init(config)を呼び出すことです。

super.init(config)は、スーパークラス側の初期化処理を実行するためのものです。自分でinitメソッドをオーバーライドする場合も、先にスーパークラスのinitを実行しておく必要があります。

initメソッドに書く処理の例

処理内容
初期値の設定カウンタや設定値を初期状態にする
共通データの準備アプリケーションスコープに初期データを保存する
接続準備データベース接続などの準備を行う

ただし、Webアプリケーション全体の初期化を特定のサーブレットのinitに任せると、リクエスト順による問題が起こることがあります。この注意点は、後半で確認します。

destroyメソッドをオーバーライドする

destroyメソッドも、HttpServletから継承しているメソッドです。

サブクラスでオーバーライドすると、サーブレットインスタンスが破棄される直前に行いたい処理を書けます。

基本形は次のようになります。

public void destroy() {
    // 最後の1回だけ実行したい処理を書く
}

destroyメソッドでは、終了時の後片付けを行います。

destroyメソッドに書く処理の例

処理内容
終了ログの出力サーブレットが終了することをコンソールに表示する
使用中リソースの解放開いていた接続やファイルなどを閉じる
一時データの整理終了前に不要な情報を片付ける

destroyメソッドは、リクエスト処理の途中で毎回実行されるものではありません。

サーブレットインスタンスが破棄される直前に実行されるため、最後に一度だけ行いたい処理を書く場所として考えます。

Eclipseでinitとdestroyを追加する方法

Eclipseでサーブレットクラスを作成するとき、継承したメソッドを選択して追加できます。

サーブレット作成画面で、initやdestroyにチェックを入れると、テンプレートとしてメソッドが作成されます。

Eclipseで追加できる主なメソッド

メソッド用途
doGetGETリクエストを処理する
doPostPOSTリクエストを処理する
initインスタンス作成直後の初期化処理を行う
destroyインスタンス破棄直前の後片付けを行う

もちろん、あとから自分でメソッドを追加してもかまいません。

Eclipseの作成画面を使うと、メソッド名や引数の書き間違いを減らせるので、慣れないうちは便利です。

initとdestroyの動作を確認するサーブレット

ここからは、実際にinitメソッドとdestroyメソッドの動作を確認できるサーブレットを作成します。

今回は、バッチ処理の進行状況確認ページをイメージしたサンプルにします。

このサーブレットでは、初回リクエスト時にinitメソッドで確認回数を0としてアプリケーションスコープへ保存します。

その後、doGetメソッドが実行されるたびに確認回数を1つ増やし、ブラウザに表示します。

destroyメソッドでは、サーブレットが破棄される直前に、コンソールへメッセージを出力します。

サンプルの動き

タイミング実行される処理
初回リクエスト時インスタンス化されたあと、initメソッドで確認回数を初期化する
リクエストごとdoGetメソッドで確認回数を増やして画面に表示する
サーバ停止や再読み込み時destroyメソッドで終了メッセージをコンソールに表示する

ブラウザには確認回数が表示されます。

Eclipseのコンソールには、initが実行されたことやdestroyが実行されたことを表すメッセージが表示されます。

initとdestroyを持つサーブレットクラスの例

ファイル名: BatchMonitorServlet.java

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/BatchMonitorServlet")
public class BatchMonitorServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // 確認回数を表すIntegerインスタンスを新規作成し、
        // アプリケーションスコープに保存
        Integer checkCount = 0;

        ServletContext application = config.getServletContext();
        application.setAttribute("batchCheckCount", checkCount);

        System.out.println("BatchMonitorServletのinitが実行されました");
    }

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {

        // アプリケーションスコープに保存された確認回数を増加
        ServletContext application = this.getServletContext();

        Integer checkCount =
                (Integer) application.getAttribute("batchCheckCount");

        checkCount++;

        application.setAttribute("batchCheckCount", checkCount);

        // HTMLを出力
        response.setContentType("text/html; charset=UTF-8");

        PrintWriter out = response.getWriter();

        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("<meta charset=\"UTF-8\">");
        out.println("<title>バッチ監視画面</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>バッチ監視画面</h1>");
        out.println("<p>進行状況の確認回数:" + checkCount + "</p>");
        out.println("<p>売上日次集計:実行中</p>");
        out.println("<p>在庫更新:待機中</p>");
        out.println("<a href=\"BatchMonitorServlet\">更新</a>");
        out.println("</body>");
        out.println("</html>");
    }

    public void destroy() {
        System.out.println("BatchMonitorServletのdestroyが実行されました");
    }
}

このサーブレットは、servletパッケージに作成します。

プロジェクト名をstudyとしている場合、ブラウザから次のURLで実行できます。

http://localhost:8080/study/BatchMonitorServlet

ブラウザの表示例

BatchMonitorServlet.javaのポイント

BatchMonitorServlet.javaでは、init、doGet、destroyの3つのメソッドを使っています。

メソッドごとの役割

メソッド役割
init初回に確認回数を0としてアプリケーションスコープへ保存する
doGetリクエストごとに確認回数を1増やして画面に表示する
destroyサーブレット破棄直前にコンソールへメッセージを出力する

initメソッドでは、Integer型のcheckCountを0で作成し、batchCheckCountという属性名でアプリケーションスコープへ保存しています。

doGetメソッドでは、アプリケーションスコープからbatchCheckCountを取得し、値を1増やしてから保存し直しています。

destroyメソッドでは、System.out.printlnを使って、destroyが実行されたことをEclipseのコンソールへ出力しています。

initで初期値を用意する

BatchMonitorServlet.javaでは、確認回数の初期値をinitメソッドで用意しています。

サーブレットインスタンスが作成された直後に次の処理が実行されます。

Integer checkCount = 0;

ServletContext application = config.getServletContext();
application.setAttribute("batchCheckCount", checkCount);

この処理によって、doGetメソッドが実行される前に、アプリケーションスコープへbatchCheckCountが保存されます。

その後、doGetメソッドではこの値を取得して、確認回数を増やします。

initで初期化するメリット

内容説明
初回だけ実行できるリクエストのたびに初期化されない
doGetの前に準備できるdoGetで使うデータを先に用意できる
初期化処理を分けられるリクエスト処理と準備処理を分離できる

初期化処理をdoGetの中に書くと、毎回初期化されてしまう可能性があります。

initに書くことで、サーブレットインスタンス生成直後の一度だけ実行する処理として整理できます。

System.out.printlnの表示先

BatchMonitorServlet.javaでは、initとdestroyの動作を確認するために、System.out.printlnを使っています。

この出力は、ブラウザには表示されません。

表示されるのは、Eclipseのコンソールビューです。

表示される場所

出力方法表示先
out.printlnブラウザ
System.out.printlnEclipseのコンソールビュー

ブラウザに表示したい内容は、PrintWriterのout.printlnでHTMLとして出力します。

サーバ側で処理の流れを確認したい内容は、System.out.printlnでコンソールに出力します。

初回リクエスト時には、コンソールにBatchMonitorServletのinitが実行されましたと表示されます。

サーバの停止やWebアプリケーションの再読み込みなどでサーブレットインスタンスが破棄されると、BatchMonitorServletのdestroyが実行されましたと表示されます。

図3:ブラウザ表示とコンソール出力の違い

この図から分かること

out.printlnで出力したHTMLは、ブラウザに表示されます。

一方、System.out.printlnで出力したメッセージは、ブラウザには表示されず、Eclipseのコンソールビューに表示されます。

initやdestroyの実行タイミングを確認したい場合は、コンソールビューを見る必要があります。

初回リクエストではinitのメッセージが表示され、サーバ停止やWebアプリケーション終了時にはdestroyのメッセージが表示されます。

動作確認の手順

BatchMonitorServlet.javaを作成したら、動作を確認してみましょう。

ブラウザから確認する方法

手順内容
1動的WebプロジェクトstudyをTomcat11_Java25に追加する
2サーバを起動する
3ブラウザでhttp://localhost:8080/study/BatchMonitorServletへアクセスする
4ブラウザに進行状況の確認回数が表示されることを確認する
5更新リンクをクリックする
6確認回数が1ずつ増えることを確認する
7Eclipseのコンソールビューにinitのメッセージが表示されることを確認する
8サーバを停止する
9Eclipseのコンソールビューにdestroyのメッセージが表示されることを確認する

Eclipseから実行する場合は、BatchMonitorServlet.javaを選択してサーバーで実行しても確認できます。

ただし、initが実行されるのは、サーブレットインスタンスが作成されたときです。すでにインスタンスが作成済みの場合、画面を更新してもinitのメッセージは毎回表示されません。

更新リンクを押すたびに増える理由

BatchMonitorServlet.javaでは、更新リンクをクリックするたびに、同じサーブレットへGETリクエストを送っています。

<a href="BatchMonitorServlet">更新</a>

このリンクをクリックすると、doGetメソッドが再び実行されます。

doGetでは、アプリケーションスコープからbatchCheckCountを取得し、1増やしてから保存し直します。

更新時の流れ

順番内容
1更新リンクをクリックする
2BatchMonitorServletへGETリクエストが送られる
3doGetメソッドが実行される
4batchCheckCountを取得する
5値を1増やす
6アプリケーションスコープに保存し直す
7画面に確認回数を表示する

initは最初の一度だけです。

更新リンクをクリックするたびに実行されるのは、doGetメソッドです。

initを使うときの注意点

initメソッドは、サーブレットインスタンスが作成された直後に実行される便利なメソッドです。

ただし、使い方には注意が必要です。

特に、Webアプリケーション全体で使うデータを、特定のサーブレットのinitで初期化する場合は気をつける必要があります。

なぜなら、initはそのサーブレットがインスタンス化されたときに実行されるからです。

通常は、対象のサーブレットに初めてリクエストが届いたときにインスタンス化されます。

つまり、そのサーブレットがまだリクエストされていなければ、initも実行されていません。

リクエスト順によって初期化が間に合わないことがある

たとえば、アプリケーション全体で使う設定情報を、ServletAのinitで作成してアプリケーションスコープに保存していたとします。

しかし、最初にリクエストされたのがServletBだった場合、ServletAのinitはまだ実行されていません。

そのため、ServletBがアプリケーションスコープから設定情報を取得しようとしても、nullになる可能性があります。

リクエスト順による問題

状況結果
ServletAが先にリクエストされるServletAのinitで設定情報が保存される
その後ServletBがリクエストされるServletBは設定情報を取得できる
ServletBが先にリクエストされるServletAのinitがまだ実行されていない
ServletBが設定情報を取得するnullになる可能性がある

このように、initの実行タイミングは、リクエストされた順番に影響されます。

Webアプリケーション全体の初期化を確実に行いたい場合は、特定のサーブレットのinitだけに頼らない設計が必要です。

Webアプリケーション全体の初期化には別の仕組みを考える

initメソッドは、そのサーブレット自身の準備には向いています。

たとえば、そのサーブレットだけで使う初期値を用意する、といった使い方です。

一方、Webアプリケーション全体で必ず必要になる初期化処理を、特定のサーブレットのinitに書くと、リクエスト順によって実行されない可能性があります。

initが向いている処理と注意が必要な処理

処理initに向いているか
そのサーブレットだけで使う初期値を用意する向いている
そのサーブレットの動作確認用カウンタを初期化する向いている
Webアプリケーション全体で必ず必要な共有データを初期化する注意が必要
ほかのサーブレットも必ず使う共通設定を初期化する注意が必要

Webアプリケーション全体に関わる初期化には、リクエスト順に左右されにくい仕組みを使うのが安全です。

このような仕組みとして、別の場面でリスナーを使う方法を学習します。

サーブレットクラスのフィールドは使えるのか

サーブレットクラスでも、通常のJavaクラスと同じようにフィールドを定義できます。

たとえば、訪問回数や確認回数を保存するためのフィールドを作ることもできます。

ただし、サーブレットクラスのフィールドは慎重に扱う必要があります。

なぜなら、サーブレットインスタンスは複数のリクエストで再利用されるからです。

つまり、サーブレット内のフィールドも、複数のリクエストで共有されることになります。

フィールドを使ったサーブレットクラスの例

次の例では、確認回数をアプリケーションスコープではなく、サーブレットクラスのフィールドとして持たせています。

ただし、このような使い方は注意が必要です。まずは動きを知るための参考例として確認しましょう。

ファイル名: FieldBatchCounterServlet.java

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

@WebServlet("/FieldBatchCounterServlet")
public class FieldBatchCounterServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private Integer checkCount;

    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        // 確認回数を初期化
        checkCount = 0;

        System.out.println("FieldBatchCounterServletのinitが実行されました");
    }

    protected void doGet(HttpServletRequest request,
            HttpServletResponse response)
            throws ServletException, IOException {

        // フィールドの確認回数を増加
        checkCount++;

        // HTMLを出力
        response.setContentType("text/html; charset=UTF-8");

        PrintWriter out = response.getWriter();

        out.println("<!DOCTYPE html>");
        out.println("<html>");
        out.println("<head>");
        out.println("<meta charset=\"UTF-8\">");
        out.println("<title>フィールドを使った確認回数</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>フィールドを使った確認回数</h1>");
        out.println("<p>確認回数:" + checkCount + "</p>");
        out.println("<a href=\"FieldBatchCounterServlet\">更新</a>");
        out.println("</body>");
        out.println("</html>");
    }

    public void destroy() {
        System.out.println("FieldBatchCounterServletのdestroyが実行されました");
    }
}

この例では、private Integer checkCountというフィールドを用意しています。

initメソッドでcheckCountに0を設定し、doGetメソッドが実行されるたびにcheckCountを1増やしています。

動作確認手順

ブラウザで http://localhost:8080/study/FieldBatchCounterServlet へアクセスします。

ブラウザの表示例

フィールドを使うときの注意点

サーブレットクラスのフィールドには、大きく2つの注意点があります。

注意点

注意点内容
ほかのサーブレットやJSPから直接参照できないフィールドはそのサーブレットインスタンス内の情報だから
同時リクエストで共有される複数のユーザーが同じフィールドを同時に使う可能性がある

まず、フィールドはそのサーブレットクラスの中にある情報です。

そのため、ほかのサーブレットやJSPから直接取得することはできません。

JSPで表示したい情報や、ほかのサーブレットでも使いたい情報は、リクエストスコープ、セッションスコープ、アプリケーションスコープなどに保存するほうが扱いやすくなります。

フィールドは複数リクエストで共有される

サーブレットインスタンスは、2回目以降のリクエストでも再利用されます。

そのため、サーブレット内のフィールドも、複数のリクエストで共有されます。

1人だけが順番にアクセスしているときは、フィールドの値がうまく増えているように見えます。

しかし、複数のユーザーがほぼ同時にアクセスすると、同じフィールドを同時に変更する可能性があります。

同時リクエストで起こり得ること

状況起こり得る問題
ユーザーAがcheckCountを取得する値が10だった
ユーザーBもほぼ同時にcheckCountを取得する同じく10だった
ユーザーAが11にして保存する11になる
ユーザーBも11にして保存する11のままになる
本来期待する値12
実際に残る可能性がある値11

このように、2人が同時にリクエストしたのに、1人分しか増えない可能性があります。

これは、アプリケーションスコープに保存した値を複数リクエストで同時に更新するときに起こる問題と似ています。

入門段階ではフィールドの変更を避ける

サーブレットクラスのフィールドは、使い方によっては便利に見えます。

しかし、同時リクエストで共有されることを考えると、安易に値を変更するフィールドを使うのは危険です。

特に、ログイン中のユーザー情報、入力途中の内容、個人ごとの状態などをサーブレットのフィールドに保存してはいけません。

フィールドに保存しないほうがよい情報

情報理由
ログイン中のユーザー情報複数ユーザーで共有される危険がある
入力途中のフォーム内容他ユーザーの情報と混ざる可能性がある
注文内容や申込内容不整合が大きな問題につながる
正確性が必要なカウンタ同時リクエストで値がずれる可能性がある

入門段階では、サーブレットクラスのフィールドを積極的に使うよりも、スコープを正しく使い分けることを優先しましょう。

ユーザーごとの情報はセッションスコープ、1回のリクエストで使う情報はリクエストスコープ、全体で共有する情報はアプリケーションスコープ、と整理して考えると安全です。

initとdestroyを学ぶとサーブレットの流れが見えてくる

initとdestroyを理解すると、サーブレットがどのように生まれ、どのように使い回され、どのように終わるのかが分かってきます。

doGetやdoPostだけを見ていると、リクエストが来たときの処理に目が向きがちです。

しかし、サーブレットには、インスタンス作成直後の初期化処理と、破棄直前の後片付け処理もあります。

サーブレットのライフサイクル

段階実行される処理
インスタンス作成直後init
リクエスト処理中doGetまたはdoPost
インスタンス破棄直前destroy

この流れをライフサイクルとして理解しておくと、サーブレットの動作をより正確にイメージできます。

initは最初の一度だけ、doGetやdoPostはリクエストごと、destroyは最後の一度だけです。

この違いを意識しながら、どの処理をどこに書くべきかを考えていきましょう。