
サーブレット&JSPの基本|Webアプリのイベントとリスナー
リクエストを待たずに自動で動く。リスナーでWebアプリケーションの開始や終了を検知しよう
前回は、サーブレットクラスのinitメソッドとdestroyメソッドについて学習しました。
initメソッドを使うと、サーブレットインスタンスが作成された直後に初期化処理を実行できます。destroyメソッドを使うと、サーブレットインスタンスが破棄される直前に後片付けの処理を実行できます。
ただし、initメソッドには注意点がありました。
initメソッドは、そのサーブレットがインスタンス化されたときに実行されます。通常は、そのサーブレットに初めてリクエストが届いたときです。
つまり、Webアプリケーション全体で必要な初期化処理を、特定のサーブレットのinitメソッドに書いてしまうと、そのサーブレットがまだリクエストされていない場合、初期化処理もまだ実行されていないことになります。
たとえば、ServletAのinitメソッドでアプリケーションスコープに共通データを保存している場合を考えます。先にServletBがリクエストされると、ServletAのinitメソッドはまだ動いていないため、ServletBは共通データを取得できない可能性があります。
このように、サーブレットのinitメソッドは、そのサーブレット自身の初期化には使いやすい一方で、Webアプリケーション全体の開始時に必ず実行したい処理には向かない場合があります。
そこで登場するのが、リスナーです。
リスナーは、Webアプリケーションで特定のイベントが発生したときに、自動的に実行される特殊なクラスです。
リクエストを受けて動くサーブレットとは違い、リスナーはWebアプリケーションの開始、終了、セッションの作成、リクエストの発生など、決まった出来事を検知して動きます。
この記事では、Webアプリケーションのイベントとリスナーの基本を確認し、Webアプリケーション開始時にアプリケーションスコープへ初期データを保存するリスナーを作成します。
リスナーとは
リスナーとは、Webアプリケーション内で特定のイベントが発生したときに、自動的に処理を実行するクラスです。
ここでいうイベントとは、Webアプリケーション内で起こる出来事のことです。
たとえば、次のような出来事がイベントです。
Webアプリケーションで発生するイベントの例
| イベント | 内容 |
|---|---|
| Webアプリケーションが開始する | サーバ起動やWebアプリケーションの読み込みによって開始される |
| Webアプリケーションが終了する | サーバ停止やWebアプリケーションの停止によって終了する |
| セッションスコープが作成される | 新しい利用者のセッションが作られる |
| セッションスコープが破棄される | ログアウトやタイムアウトなどでセッションが終わる |
| リクエストが発生する | ブラウザからリクエストが送られる |
| レスポンスが完了する | リクエストに対する処理が終わる |
サーブレットは、ブラウザからURLに対してリクエストされたときに動きます。
一方、リスナーは、特定のイベントが発生したときに動きます。
この違いを理解しておくと、リスナーの役割が見えてきます。
サーブレットとリスナーの違い
| 種類 | 実行されるきっかけ | 主な用途 |
|---|---|---|
| サーブレット | ブラウザからのリクエスト | 画面表示、フォーム送信、処理の受付 |
| リスナー | Webアプリケーション内のイベント | 開始時の初期化、終了時の後片付け、スコープの監視 |
リスナーを使うと、リクエストされる順番に左右されず、Webアプリケーションの状態に合わせて処理を実行できます。
図1:イベントを検知して動作するリスナー

この図から分かること
リスナーは、Webアプリケーション内で発生するイベントをきっかけに動作します。
サーブレットは、ブラウザからのリクエストによってdoGetやdoPostが実行されます。一方、リスナーは、Webアプリケーションが開始された、セッションが作成された、リクエストが発生した、といった出来事を検知してメソッドを実行します。
このため、リスナーを使うと、特定のサーブレットが先にリクエストされるかどうかに左右されず、Webアプリケーションの状態に合わせた処理を書けます。
リスナーを使うと何ができるのか
リスナーを使うと、リクエストとは別のタイミングで処理を行えます。
たとえば、Webアプリケーションが開始されたときに、アプリケーションスコープへ初期データを保存できます。
これは、特定のサーブレットのinitメソッドで初期化するよりも、Webアプリケーション全体の準備処理として分かりやすい方法です。
リスナーが向いている処理
| 処理 | 理由 |
|---|---|
| Webアプリケーション開始時の初期化 | リクエスト順に左右されずに実行できる |
| Webアプリケーション終了時の後片付け | 終了イベントに合わせて処理できる |
| セッション作成数の確認 | セッションが作られたタイミングを検知できる |
| リクエストの開始や終了の監視 | リクエストごとの処理を追跡できる |
| スコープ属性の追加や削除の監視 | 属性が保存、上書き、削除されたことを検知できる |
リスナーは、画面を表示するためのクラスではありません。
利用者から直接リクエストされるクラスでもありません。
Webアプリケーションの裏側で、特定のイベントに反応して処理を行う補助的なクラスだと考えると分かりやすいです。
リスナーはインタフェースを実装して作成する
リスナーは、イベントの種類に応じて用意されているリスナーインタフェースを実装して作成します。
どのイベントに反応したいかによって、実装するインタフェースが変わります。
たとえば、Webアプリケーションの開始や終了に反応したい場合は、ServletContextListenerインタフェースを実装します。
セッションスコープの作成や破棄に反応したい場合は、HttpSessionListenerインタフェースを実装します。
リクエストの発生やレスポンスの完了に反応したい場合は、ServletRequestListenerインタフェースを実装します。
イベントと対応するリスナーインタフェース
| イベント | リスナーインタフェース |
|---|---|
| Webアプリケーションが開始または終了する | ServletContextListener |
| アプリケーションスコープにインスタンスを保存、上書き保存、またはスコープから削除する | ServletContextAttributeListener |
| セッションスコープを作成または破棄する | HttpSessionListener |
| セッションスコープにインスタンスを保存、上書き保存、またはスコープから削除する | HttpSessionAttributeListener |
| セッションスコープが待避、または回復する | HttpSessionActivationListener |
| このインタフェースを実装したクラスのインスタンスをセッションスコープに保存、またはスコープから削除する | HttpSessionBindingListener |
| リクエストが発生する、またはレスポンスが完了する | ServletRequestListener |
| リクエストスコープにインスタンスを保存、上書き保存、またはスコープから削除する | ServletRequestAttributeListener |
このように、リスナーインタフェースはイベントごとに分かれています。
どのイベントを扱いたいのかを決めてから、対応するインタフェースを選びます。
Webアプリケーション開始時に動くリスナー
今回は、Webアプリケーションが開始されたときに動くリスナーを作成します。
Webアプリケーションの開始に対応するには、ServletContextListenerインタフェースを実装します。
ServletContextListenerには、主に次の2つのメソッドがあります。
ServletContextListenerインタフェースのメソッド
| メソッド | 実行のきっかけとなるイベント |
|---|---|
| contextInitialized | Webアプリケーションが開始する |
| contextDestroyed | Webアプリケーションが終了する |
contextInitializedメソッドは、Webアプリケーションが開始されたときに実行されます。
contextDestroyedメソッドは、Webアプリケーションが終了するときに実行されます。
今回のサンプルでは、Webアプリケーション開始時にアクセス確認回数を0で用意し、アプリケーションスコープに保存します。
図2:Webアプリケーション開始時にリスナーで初期化する

この図から分かること
Webアプリケーションが開始されると、ServletContextListenerを実装したリスナーが動作します。
contextInitializedメソッドでは、ServletContextEventからServletContextを取得できます。
ServletContextはアプリケーションスコープの正体です。そのため、context.setAttributeを使うことで、Webアプリケーション開始時にアプリケーションスコープへ初期データを保存できます。
この方法なら、特定のサーブレットが最初にリクエストされるかどうかに左右されず、Webアプリケーション開始時に処理を実行できます。
WebListenerアノテーションを付ける
リスナーとして動作させるクラスには、WebListenerアノテーションを付けます。
WebListenerアノテーションを付けることで、アプリケーションサーバがそのクラスをリスナーとして認識します。
WebListenerアノテーションの役割
| 項目 | 内容 |
|---|---|
| アノテーション | @WebListener |
| 役割 | クラスをリスナーとして登録する |
| 必要なインポート | jakarta.servlet.annotation.WebListener |
| 実行タイミング | 対応するイベントが発生したとき |
WebListenerアノテーションを付けたリスナーは、Webアプリケーション開始時など、対応するイベントが発生したときにサーブレットコンテナによって扱われます。
リスナーでアプリケーションスコープを初期化する
ここでは、Webアプリケーション開始時にアクセス確認回数を0としてアプリケーションスコープへ保存するリスナーを作成します。
前回のinitメソッドでは、特定のサーブレットが初めてリクエストされたときに初期化処理が実行されました。
今回のリスナーでは、Webアプリケーションが開始されたタイミングで初期化処理を実行します。
これにより、リクエスト順に左右されず、アプリケーションスコープへ初期データを用意できます。
Webアプリケーションの開始に対応するリスナーの例
ファイル名: AppStartListener.java
package listener;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
@WebListener
public class AppStartListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
Integer accessCount = 0;
context.setAttribute("accessCount", accessCount);
System.out.println("AppStartListenerのcontextInitializedが実行されました");
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("AppStartListenerのcontextDestroyedが実行されました");
}
}AppStartListener.javaは、listenerパッケージに作成します。
このクラスはServletContextListenerインタフェースを実装しています。
Webアプリケーションが開始されると、contextInitializedメソッドが実行されます。ここでは、Integer型のaccessCountを0で作成し、アプリケーションスコープに保存しています。
Webアプリケーションが終了すると、contextDestroyedメソッドが実行されます。ここでは、動作確認のためにコンソールへメッセージを出力しています。
AppStartListener.javaのポイント
AppStartListener.javaでは、Webアプリケーションの開始と終了に対応する処理を記述しています。
AppStartListener.javaで行っていること
| 処理 | 内容 |
|---|---|
| WebListenerを付ける | リスナーとして登録する |
| ServletContextListenerを実装する | Webアプリケーション開始と終了のイベントに対応する |
| contextInitializedを実装する | Webアプリケーション開始時の処理を書く |
| contextDestroyedを実装する | Webアプリケーション終了時の処理を書く |
| ServletContextを取得する | アプリケーションスコープを操作する |
| accessCountを保存する | 初期値0をアプリケーションスコープに保存する |
contextInitializedメソッドでは、引数としてServletContextEventが渡されます。
このServletContextEventからgetServletContextを実行すると、ServletContextを取得できます。
ServletContextはアプリケーションスコープの正体なので、setAttributeを使ってaccessCountを保存できます。
contextInitializedで初期化する
contextInitializedメソッドは、Webアプリケーションが開始されたときに実行されます。
今回の例では、次の流れで初期化処理を行っています。
contextInitializedの流れ
| 順番 | 処理 | 内容 |
|---|---|---|
| 1 | ServletContextを取得する | sce.getServletContextで取得する |
| 2 | Integerを作成する | accessCountの初期値として0を用意する |
| 3 | アプリケーションスコープに保存する | context.setAttributeで保存する |
| 4 | コンソールへ出力する | 実行されたことを確認する |
この処理により、Webアプリケーションが開始された時点で、アプリケーションスコープにaccessCountが用意されます。
特定のサーブレットが先にリクエストされる必要はありません。
contextDestroyedで終了処理を書く
contextDestroyedメソッドは、Webアプリケーションが終了するときに実行されます。
今回の例では、動作確認のためにSystem.out.printlnでメッセージを出力しています。
Webアプリケーション終了時に後片付けが必要な場合は、contextDestroyedメソッドに処理を書きます。
contextDestroyedに書ける処理の例
| 処理 | 内容 |
|---|---|
| 終了ログの出力 | Webアプリケーション終了をコンソールへ表示する |
| 共有リソースの後片付け | Webアプリケーション全体で使っていたリソースを整理する |
| 一時データの整理 | 終了前に必要な整理処理を行う |
今回は、Webアプリケーション開始時の初期化が中心なので、contextDestroyedでは簡単なコンソール出力だけにしています。
リスナーを作成したあとの動作確認
AppStartListener.javaを作成したら、サーバを再起動して動作を確認します。
リスナーは、通常のサーブレットのようにブラウザから直接リクエストして実行するものではありません。
Webアプリケーション開始イベントが発生したときに、自動的に実行されます。
動作確認の流れ
| 手順 | 内容 |
|---|---|
| 1 | AppStartListener.javaをlistenerパッケージに作成する |
| 2 | 動的WebプロジェクトstudyをTomcat11_Java25に追加する |
| 3 | サーバを再起動する |
| 4 | Webアプリケーションstudyが開始される |
| 5 | contextInitializedが自動的に実行される |
| 6 | Eclipseのコンソールビューに実行メッセージが表示される |
| 7 | Webアプリケーション終了時にcontextDestroyedのメッセージも確認する |
この確認で大切なのは、リスナーがURLへのリクエストではなく、Webアプリケーションの開始イベントで実行されることです。
ブラウザでAppStartListener.javaを直接開くわけではありません。
initによる初期化との違い
initメソッドでも、初期化処理を書くことはできます。
しかし、initメソッドはサーブレットごとに実行されます。
そのため、そのサーブレットがまだリクエストされていなければ、initメソッドもまだ実行されていません。
一方、ServletContextListenerのcontextInitializedは、Webアプリケーション開始時に実行されます。
initとリスナーの違い
| 項目 | initメソッド | リスナーのcontextInitialized |
|---|---|---|
| 実行される単位 | サーブレットごと | Webアプリケーションごと |
| 実行されるきっかけ | サーブレットインスタンスの作成 | Webアプリケーションの開始 |
| リクエスト順の影響 | 受ける場合がある | 受けにくい |
| 向いている処理 | そのサーブレット自身の初期化 | Webアプリケーション全体の初期化 |
この違いにより、Webアプリケーション全体で使うデータを初期化したい場合は、リスナーのほうが適しています。
特定のサーブレットのinitに初期化処理を書くと、そのサーブレットが最初に呼ばれる前提になってしまうことがあります。
図3:initとリスナーによる初期化の違い

この図から分かること
initメソッドは、対象のサーブレットがインスタンス化されたときに実行されます。
そのため、ServletAのinitでアプリケーションスコープに初期データを保存している場合、ServletAがまだリクエストされていなければ、その初期化処理は実行されていません。
一方、ServletContextListenerのcontextInitializedは、Webアプリケーション開始時に実行されます。
そのため、ServletAやServletBのリクエスト順に左右されず、Webアプリケーション全体で使う初期データを用意できます。
CounterServlet側のinit処理は不要になる
Webアプリケーション開始時にリスナーで初期データを保存できるようになると、同じ初期化処理をサーブレットのinitメソッドに書く必要はありません。
たとえば、アクセス回数を表すaccessCountをリスナーでアプリケーションスコープに保存するなら、アクセス回数を表示するサーブレット側では、その値を取得して利用すればよくなります。
役割分担の考え方
| クラス | 役割 |
|---|---|
| AppStartListener.java | Webアプリケーション開始時にaccessCountを初期化する |
| アクセス回数を表示するサーブレット | アプリケーションスコープからaccessCountを取得して利用する |
このように、初期化処理をリスナーに分けると、サーブレットはリクエスト処理に集中しやすくなります。
また、Webアプリケーション開始時に初期化が完了しているため、リクエストされる順番を気にしなくて済みます。
リスナーの作り方
リスナーは、決まった手順で作成できます。
難しそうに見えますが、作り方の流れはとても整理されています。
リスナー作成の手順
| 手順 | 内容 |
|---|---|
| 1 | WebListenerアノテーションを付ける |
| 2 | 対応したいイベントのリスナーインタフェースを実装する |
| 3 | リスナーインタフェースのメソッドを実装する |
| 4 | メソッド内に実行したい処理を書く |
たとえば、Webアプリケーション開始時のイベントに対応する場合は、ServletContextListenerを実装します。
そして、Webアプリケーション開始時に実行したい処理をcontextInitializedに書きます。
Webアプリケーション終了時に実行したい処理がある場合は、contextDestroyedに書きます。
Eclipseでリスナーを作成する場合
Eclipseでは、リスナーを作成するための画面を使うこともできます。
その場合、WebListenerアノテーションの付与、リスナーインタフェースの実装、メソッドのひな形作成などをEclipseが補助してくれます。
Eclipseで補助される内容
| 作業 | Eclipseの補助 |
|---|---|
| WebListenerアノテーションの付与 | 自動で付けられる |
| リスナーインタフェースの実装 | 選択したイベントに応じて指定される |
| メソッドの作成 | 必要なメソッドのひな形が作られる |
| import文の追加 | 必要なクラスを自動で追加できる |
Eclipseの機能を使うと、メソッド名やimport文の書き間違いを減らせます。
ただし、どのイベントに対して、どのリスナーインタフェースを使うのかは理解しておく必要があります。
リスナーの作成
動的Webプロジェクトを選択して右クリック→「新規」→「クラス」をクリックします。

リスナーが所属するパッケージとクラス名を指定し、「完了」をクリックします。

作成したクラスに変更を加えます。
リスナーを使うときに意識したいこと
リスナーは、リクエスト処理とは違うタイミングで動くクラスです。
そのため、サーブレットと同じ感覚で直接URLを指定して実行しようとすると、動作のイメージがずれてしまいます。
意識したいポイント
| ポイント | 内容 |
|---|---|
| リスナーはURLで直接呼び出さない | イベントが発生したときに自動で動く |
| イベントに合わせてインタフェースを選ぶ | 開始、終了、セッション、リクエストなどで異なる |
| WebListenerを付ける | リスナーとして登録する |
| アプリケーションスコープの初期化に使える | Webアプリケーション開始時に実行できる |
| リクエスト順に左右されにくい | 特定のサーブレットの初回リクエストを待たなくてよい |
リスナーを理解すると、Webアプリケーション全体の開始や終了、セッションやリクエストの発生など、サーブレットだけでは扱いにくいタイミングの処理を書けるようになります。
特に、Webアプリケーション全体で使う初期データを用意したい場面では、ServletContextListenerが役立ちます。
