
サーブレット&JSPの基本|アプリケーションスコープの注意点とスコープ比較
全ユーザーで共有できるからこそ注意が必要。アプリケーションスコープの落とし穴とスコープの使い分けを理解しよう
アプリケーションスコープは、Webアプリケーション全体でインスタンスを共有できる便利なスコープです。
リクエストスコープは1回のリクエスト内、セッションスコープはユーザーごと、アプリケーションスコープはWebアプリケーション全体で使う、という違いがありました。
前回作成した評価ボタン機能では、教材ページに対して役に立ったやもう少しをクリックした人数を、アプリケーションスコープに保存しました。評価数は特定のユーザーだけの情報ではなく、すべてのユーザーで共有したい情報なので、アプリケーションスコープに向いているように見えます。
しかし、アプリケーションスコープは便利な反面、扱い方を間違えるとトラブルの原因になります。
特に注意したいのが、同時アクセスによる不整合と、インスタンスの保存期間です。
この記事では、評価ボタン機能を例にしながら、アプリケーションスコープで起こりやすい問題を確認します。そのうえで、リクエストスコープ、セッションスコープ、アプリケーションスコープの違いを整理し、どの場面でどのスコープを選べばよいのかを考えていきます。
アプリケーションスコープは全ユーザーで共有される
アプリケーションスコープは、1つのWebアプリケーションにつき1つだけ作成されます。
そのため、同じWebアプリケーションを利用しているすべてのユーザーが、同じアプリケーションスコープを参照します。
たとえば、PageFeedbackインスタンスをpageFeedbackという属性名でアプリケーションスコープに保存した場合、青山さんがアクセスしても、山田さんがアクセスしても、同じPageFeedbackインスタンスを取得できます。
アプリケーションスコープの共有イメージ
| 利用者 | 取得するインスタンス |
|---|---|
| 青山さん | アプリケーションスコープ内のpageFeedback |
| 山田さん | アプリケーションスコープ内のpageFeedback |
| 佐藤さん | アプリケーションスコープ内のpageFeedback |
このように、全ユーザーで同じインスタンスを使うため、共通のお知らせや全体の評価数などには利用しやすいスコープです。
一方で、全ユーザーが同じインスタンスを使うということは、複数のユーザーが同じタイミングでそのインスタンスを更新する可能性がある、ということでもあります。
注意したいトラブル
アプリケーションスコープで特に注意したい点は、次の2つです。
アプリケーションスコープ利用時の注意点
| 注意点 | 内容 |
|---|---|
| 同時アクセスによる不整合 | 複数のリクエストが同じインスタンスを同時に更新すると、値がずれることがある |
| インスタンスの保存期間 | Webアプリケーションが終了すると消え、削除しなければメモリに残り続ける |
評価ボタン機能のように、数値を増やす処理では、同時アクセスによる不整合が起こりやすくなります。
また、アプリケーションスコープにはセッションスコープのようなタイムアウトがありません。不要なインスタンスを保存したままにすると、メモリを圧迫する原因になります。
図1:アプリケーションスコープで共有される評価情報

この図から分かること
アプリケーションスコープに保存したインスタンスは、Webアプリケーション全体で共有されます。
青山さん、山田さん、佐藤さんがそれぞれ別のブラウザからアクセスしても、同じpageFeedbackインスタンスを取得します。
この性質により、教材ページの評価数のように、全ユーザーで共通して見たい情報を扱えます。ただし、全員が同じインスタンスを利用するため、同時に更新が行われると値の不整合が起こる可能性があります。
注意点① 同時アクセスによる不整合
アプリケーションスコープに保存されているインスタンスを、複数のリクエストがほぼ同じタイミングで更新すると、不整合が起こる場合があります。
たとえば、教材ページ評価ボタン機能で、役に立ったの数が10人だったとします。
そこへ、青山さんと山田さんがほぼ同時に役に立ったをクリックしたとします。
本来であれば、10人から2人分増えて12人になってほしいところです。
しかし、処理のタイミングによっては、11人にしかならないことがあります。
なぜ1人分しか増えないのか
評価数を増やす処理では、次のような流れが行われます。
評価数を増やす基本の流れ
| 順番 | 内容 |
|---|---|
| 1 | アプリケーションスコープからPageFeedbackを取得する |
| 2 | 現在の役に立ったの数を取得する |
| 3 | 取得した数に1を足す |
| 4 | 更新後の値をPageFeedbackに設定する |
| 5 | アプリケーションスコープに保存する |
1人だけがクリックする場合は、この流れで問題なく動きます。
しかし、2人がほぼ同じタイミングでクリックすると、どちらの処理も更新前の10を取得してしまうことがあります。
その結果、青山さんの処理も10から11に更新し、山田さんの処理も10から11に更新します。
最終的に保存される値は11になり、2人がクリックしたのに1人分しか増えていないように見えてしまいます。
同時アクセスで起こるずれ
| タイミング | 青山さんの処理 | 山田さんの処理 |
|---|---|---|
| 最初の状態 | 役に立ったは10人 | 役に立ったは10人 |
| 取得 | 10を取得する | 10を取得する |
| 加算 | 10に1を足して11にする | 10に1を足して11にする |
| 保存 | 11を保存する | 11を保存する |
| 結果 | 2回クリックされたのに11人になる | 期待値は12人 |
このように、同じインスタンスを複数のリクエストが同時に更新すると、更新のタイミングが重なり、期待した結果にならない場合があります。
図2:ほぼ同時にクリックされると不整合が起こる

この図から分かること
アプリケーションスコープに保存されたインスタンスは、すべてのユーザーで共有されます。
そのため、複数のユーザーがほぼ同時に評価ボタンをクリックすると、同じPageFeedbackインスタンスを同時に更新することがあります。
どちらの処理も更新前の値を取得してしまうと、2人がクリックしても1人分しか増えないことがあります。これは、同時アクセスによって更新処理が競合している状態です。
不整合が問題になるデータは保存しない
同時アクセスによる不整合が大きな問題になるデータは、アプリケーションスコープに保存しないほうが安全です。
評価ボタンのような簡単なサンプルでは、1人分のずれが学習用として許容できる場合もあります。
しかし、在庫数、残席数、決済金額、申込人数の上限など、正確な更新が求められるデータでは、不整合が致命的な問題になることがあります。
アプリケーションスコープでの更新に注意が必要な情報
| 情報 | 注意が必要な理由 |
|---|---|
| 在庫数 | 同時購入で数がずれると販売数に影響する |
| 残席数 | 同時申込で定員を超える可能性がある |
| 金額 | 更新のずれが直接トラブルにつながる |
| 重要な集計値 | 正確な数値が必要になる |
このような重要なデータは、アプリケーションスコープではなく、ファイルやデータベースなど、適切な管理方法を使うことを考えます。
また、アプリケーションスコープを使う場合でも、保存は一度だけにして、その後は更新せずに取得だけにする使い方であれば、不整合のリスクを減らせます。
更新が必要な場合は競合への対応が必要
アプリケーションスコープに保存されたインスタンスをどうしても更新する必要がある場合は、同時アクセスによる競合に対応する必要があります。
Webアプリケーションでは、リクエストごとに処理が実行されます。複数のリクエストが同時に届くと、それぞれの処理が並行して進むことがあります。
この処理の単位をスレッドと考えると分かりやすいです。
スレッドとして考える例
| 処理 | 内容 |
|---|---|
| 青山さんのリクエスト処理 | 1つのスレッドとして実行される |
| 山田さんのリクエスト処理 | 別のスレッドとして実行される |
| 同じインスタンスの更新 | 複数のスレッドが同時に触る可能性がある |
同じインスタンスを複数のスレッドが同時に更新すると、値のずれが起こることがあります。
そのため、どうしても更新が必要な処理では、スレッドによる競合を調停する仕組みが必要になります。
ただし、この段階では、アプリケーションスコープに保存したインスタンスを複数ユーザーが同時に更新すると不整合が起こる場合がある、という考え方をしっかり押さえておきましょう。
注意点② インスタンスの保存期間
アプリケーションスコープに保存したインスタンスは、Webアプリケーションが終了すると消滅します。
ブラウザを閉じても、アプリケーションスコープの内容はすぐには消えません。
しかし、サーバを停止したり再起動したり、Webアプリケーションが終了したりすると、アプリケーションスコープに保存されていたインスタンスは利用できなくなります。
アプリケーションスコープの保存期間
| 操作 | アプリケーションスコープの内容 |
|---|---|
| 同じWebアプリケーションが動き続けている | 保存されたインスタンスを取得できる |
| ブラウザを閉じる | 基本的にはアプリケーションスコープの内容は残る |
| Webアプリケーションを終了する | 保存されたインスタンスは消滅する |
| サーバを停止または再起動する | 保存されたインスタンスは消滅する |
アプリケーションスコープは、Webアプリケーションが動いている間だけ利用できる保存領域です。
Webアプリケーションを再開したあとも使いたいデータは、アプリケーションスコープではなく、ファイルやデータベースなどアプリケーションの外に保存する必要があります。
長期間残したいデータは外部に保存する
アプリケーションスコープは、サーバのメモリ上にインスタンスを保存します。
そのため、Webアプリケーションが終了すると内容は消えます。
評価数のように、サーバを再起動しても残したいデータを扱う場合は、アプリケーションスコープだけでは不十分です。
保存先の考え方
| 保存したい期間 | 向いている保存先 |
|---|---|
| 1回のリクエスト中だけ | リクエストスコープ |
| ユーザーの操作中だけ | セッションスコープ |
| Webアプリケーション起動中だけ | アプリケーションスコープ |
| Webアプリケーション終了後も残したい | ファイルやデータベース |
アプリケーションスコープは、永続的な保存場所ではありません。
Webアプリケーションが終了しても残したいデータは、アプリケーションの外に保存する必要があります。
アプリケーションスコープにはタイムアウトがない
セッションスコープにはセッションタイムアウトがあります。
一定時間利用されていないセッションは、サーバによって破棄されます。
一方、アプリケーションスコープには、セッションスコープのようなタイムアウトはありません。
そのため、アプリケーションスコープに保存したインスタンスは、削除するかWebアプリケーションが終了するまで残ります。
セッションスコープとの違い
| 項目 | セッションスコープ | アプリケーションスコープ |
|---|---|---|
| 主な単位 | ユーザーごと | Webアプリケーションごと |
| タイムアウト | ある | ない |
| 削除される主なタイミング | セッションタイムアウト、削除、破棄 | 削除、Webアプリケーション終了 |
| 残り続ける危険 | ユーザーごとの情報が残る | アプリ全体の情報が残る |
大量のインスタンスをアプリケーションスコープに保存したままにすると、メモリを圧迫し続けます。
不要になったインスタンスは、removeAttributeを使って明示的に削除することを考えます。
図3:スコープの保存期間と共有範囲の違い

この図から分かること
リクエストスコープ、セッションスコープ、アプリケーションスコープは、保存できる範囲と期間が異なります。
リクエストスコープは1回のリクエスト中だけ利用します。セッションスコープはユーザーごとに情報を保存します。アプリケーションスコープはWebアプリケーション全体で情報を共有します。
同じsetAttributeやgetAttributeを使っても、どのスコープを使うかによって、保存したインスタンスを誰が、いつまで利用できるかが変わります。
スコープを比較する
ここまで、リクエストスコープ、セッションスコープ、アプリケーションスコープを学習してきました。
それぞれのスコープは、インスタンスを保存できる点では共通しています。
ただし、作成される単位、利用できる期間、リクエストをまたげるかどうか、ユーザーごとの情報を保存できるかどうかが違います。
各スコープの特徴
| 項目 | リクエストスコープ | セッションスコープ | アプリケーションスコープ |
|---|---|---|---|
| インスタンス | HttpServletRequest | HttpSession | ServletContext |
| 暗黙オブジェクト | request | session | application |
| 作成される単位 | リクエストごと | ユーザーごと、ブラウザごと | アプリケーションごと |
| 保存したインスタンスが取得できる期間 | 削除するか、レスポンスするまで | 削除するか、セッションタイムアウトするまで | 削除するか、アプリケーションが終了するまで |
| リクエストをまたいでインスタンスを保存 | できない | できる | できる |
| ユーザーごとのインスタンスを保存 | できる、ただしリクエストごとに保存する | できる | できない、全ユーザーで共有する |
この表を見ると、3つのスコープは似ているようで、かなり性質が違うことが分かります。
スコープを選ぶときは、保存したいインスタンスを誰が使うのか、いつまで使うのかを考えることが大切です。
リクエストスコープが向いている場面
リクエストスコープは、1回のリクエストの中だけで使うデータに向いています。
たとえば、サーブレットで処理した結果をJSPへ渡して表示するだけなら、リクエストスコープで十分です。
リクエストスコープが向いている情報
| 情報 | 理由 |
|---|---|
| 入力結果の一時表示 | レスポンス後に残す必要がない |
| 検索結果の表示 | その画面表示だけで使う |
| エラーメッセージ | フォワード先のJSPで表示できればよい |
| 診断結果 | 1回の結果画面で表示できればよい |
リクエストスコープは、レスポンスが返ると使えなくなります。
そのため、次のリクエストでも同じ情報を使いたい場合には向いていません。
セッションスコープが向いている場面
セッションスコープは、ユーザーごとに情報を保存したい場合に向いています。
ログイン中のユーザー情報や、入力画面から確認画面、完了画面へ進むときの一時的な情報などに使います。
セッションスコープが向いている情報
| 情報 | 理由 |
|---|---|
| ログイン中のユーザー情報 | ユーザーごとに分ける必要がある |
| 入力から確認まで保持する情報 | リクエストをまたいで使いたい |
| 個人の操作状態 | 他のユーザーと共有してはいけない |
| 一連の画面遷移で使うデータ | 同じユーザーの操作中だけ保持したい |
セッションスコープはリクエストをまたげますが、全ユーザーで共有する情報には向いていません。
ユーザーごとの情報を扱う場合に利用します。
アプリケーションスコープが向いている場面
アプリケーションスコープは、Webアプリケーション全体で共有したい情報に向いています。
全ユーザーで同じ値を見たり、同じインスタンスを利用したりする場合に使います。
アプリケーションスコープが向いている情報
| 情報 | 理由 |
|---|---|
| 共通のお知らせ | 全ユーザーに同じ内容を表示したい |
| 教材ページの評価数 | 全ユーザーで同じ数を共有したい |
| アプリケーション共通の設定情報 | 複数のサーブレットやJSPで共通利用したい |
| 起動中だけ使う共有データ | Webアプリケーションが動いている間だけ利用したい |
アプリケーションスコープは、ユーザーごとに分ける必要がある情報には向いていません。
また、同時に更新される可能性がある重要なデータを保存する場合は、不整合が起こらないように注意が必要です。
スコープ選びの考え方
スコープを選ぶときは、次の順番で考えると整理しやすくなります。
スコープ選びの目安
| 質問 | 選ぶスコープ |
|---|---|
| その画面表示だけで使えればよいか | リクエストスコープ |
| 同じユーザーの次の画面でも使いたいか | セッションスコープ |
| すべてのユーザーで共有したいか | アプリケーションスコープ |
| Webアプリケーション終了後も残したいか | ファイルやデータベース |
スコープは、何となく選ぶのではなく、保存したいデータの性質に合わせて選びます。
どの範囲で使うのか、いつまで残したいのか、誰に見せるのかを考えると、適切なスコープを選びやすくなります。
ページスコープについて
スコープには、リクエストスコープ、セッションスコープ、アプリケーションスコープのほかに、ページスコープもあります。
ページスコープは、1つのJSPページの中で利用されるスコープです。
ただし、ServletとJSPを使った基本的なWebアプリケーション開発では、ページスコープを意識的に使う場面は多くありません。
そのため、まずはリクエストスコープ、セッションスコープ、アプリケーションスコープの3つをしっかり理解することが大切です。
まず押さえたい3つのスコープ
| 優先して理解したいスコープ | 理由 |
|---|---|
| リクエストスコープ | サーブレットからJSPへデータを渡す基本になる |
| セッションスコープ | ユーザーごとの情報をリクエストをまたいで扱える |
| アプリケーションスコープ | Webアプリケーション全体で共有する情報を扱える |
この3つを使い分けられるようになると、ServletとJSPで作れるWebアプリケーションの幅が広がります。
コンテキストとは
ServletContextのContextは、Webアプリケーションを表します。
WebアプリケーションをリクエストするURLでは、サーバ名のあとにコンテキストの名前を指定します。
URLの基本形は次のように考えます。
たとえば、動的Webプロジェクト名がstudyの場合、デフォルトではコンテキストの名前もstudyになります。
そのため、LessonIndexを実行する場合は、次のようなURLになります。
URLとコンテキストの関係
| URLの部分 | 内容 |
|---|---|
| localhost:8080 | サーバとポート番号 |
| study | コンテキストの名前 |
| LessonIndex | サーブレットのURLパターン |
デフォルトでは、動的Webプロジェクトの名前がそのままコンテキスト名になります。
そのため、プロジェクト名studyで作成したWebアプリケーションでは、URLにもstudyが入ります。
ServletContextはWebアプリケーション全体を表す
ServletContextは、Webアプリケーション全体を表すオブジェクトです。
アプリケーションスコープを操作するときにServletContextを使うのは、アプリケーションスコープがWebアプリケーション全体に属しているからです。
ServletContextの考え方
| 項目 | 内容 |
|---|---|
| Contextの意味 | Webアプリケーション |
| ServletContext | Webアプリケーション全体を表すインスタンス |
| アプリケーションスコープ | ServletContextを通して操作する |
| JSPでの暗黙オブジェクト | application |
サーブレットではgetServletContextでServletContextを取得します。
JSPでは暗黙オブジェクトapplicationを使ってアプリケーションスコープを操作できます。
このように、ServletContextはアプリケーションスコープの理解に関わる大切な考え方です。
アプリケーションスコープで確認したいこと
アプリケーションスコープを使うときは、次の点を確認しましょう。
| 確認項目 | 内容 |
|---|---|
| 全ユーザーで共有してよい情報か | 個人ごとの情報を保存していないか確認する |
| 同時更新されても問題ないか | 競合による不整合が致命的にならないか確認する |
| 更新が本当に必要か | 保存は一度だけにして取得中心にできないか考える |
| 長期保存が必要か | Webアプリケーション終了後も残したいなら外部保存を考える |
| 不要なインスタンスを削除しているか | removeAttributeで整理する |
| サーバ再起動で消えることを理解しているか | アプリケーションスコープは永続保存ではない |
| ほかのスコープと使い分けているか | request、session、applicationの範囲を意識する |
アプリケーションスコープは、全ユーザーで共有できる便利なスコープです。
ただし、共有範囲が広い分、同時アクセスや保存期間には注意が必要です。
ServletとJSPでWebアプリケーションを作るときは、リクエストスコープ、セッションスコープ、アプリケーションスコープの違いを理解し、データの性質に合わせて使い分けましょう。
