メインコンテンツまでスキップ

Java Servlet

Spring Bootで@RestControllerを書くと、HTTPリクエストを簡単に処理できます。しかし、その裏側ではJava Servletという技術が動いています。Servletを理解することで、Webアプリケーションの「本質」が見えてきます。


Servletとは何か

本質的な役割

┌─────────────────────────────────────────────────────────────┐
│ Servletの本質 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Servlet = 「HTTPリクエストを受けて、レスポンスを返す」 │
│ という契約(インターフェース) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ HTTP Request ──→ Servlet ──→ HTTP Response │ │
│ │ │ │
│ │ 「何が来て」 「処理して」 「何を返すか」 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 重要なのは: │
│ ・Servletは「仕様」であり「実装」ではない │
│ ・Jakarta EE(旧Java EE)の標準仕様 │
│ ・どのServletコンテナでも同じように動く │
│ │
└─────────────────────────────────────────────────────────────┘

技術スタックにおける位置づけ

┌─────────────────────────────────────────────────────────────┐
│ Servletの位置づけ │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ あなたのアプリケーション │ │
│ │ (ビジネスロジック) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Spring Boot / Spring MVC │ │
│ │ (高レベルな抽象化) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Java Servlet API ← ここを学ぶ │ │
│ │ (HTTPの抽象化) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servletコンテナ (Tomcat, Jetty, Undertow) │ │
│ │ (実行環境) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ TCP/IP ソケット │ │
│ │ (ネットワーク通信) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Servletは「生のソケット通信」と「高レベルFW」の間にある │
│ HTTPプロトコルを抽象化した「ちょうどいい」レイヤー │
│ │
└─────────────────────────────────────────────────────────────┘

Servletコンテナ・Servlet API・Spring Bootの関係

この3つの関係は、よく混同されます。それぞれの役割を明確にしましょう。

┌─────────────────────────────────────────────────────────────┐
│ 3者の関係 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servlet API(仕様 = interface) │ │
│ │ ・「HTTPをどう扱うか」のインターフェース定義 │ │
│ │ ・Jakarta EE の標準仕様 │ │
│ │ ・HttpServletRequest, Filter, Listener などを定義 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↑ 実装する ↑ 利用する │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ Servletコンテナ │ │ Spring Boot(利用者) │ │
│ │ ・Servlet仕様の │ │ ・Servlet API上に構築 │ │
│ │ 実行環境 │ │ ・より高レベルな抽象化 │ │
│ │ ・HTTPパース │ │ ・@RestController等 │ │
│ │ ・スレッド管理 │ │ ・自動設定 │ │
│ │ ・ライフサイクル │ │ ・コンテナを組み込む │ │
│ │ │ │ │ │
│ │ 例: │ │ │ │
│ │ Tomcat, Jetty, │ │ │ │
│ │ Undertow 等 │ │ │ │
│ └──────────────────┘ └──────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ それぞれの責務 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【Servlet API】= 契約(interface / 抽象クラス) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 「HTTPリクエストが来たら、こういうメソッドを呼ぶ」 │ │
│ │ 「レスポンスはこうやって返す」 │ │
│ │ という約束事を定義(実装は持たない) │ │
│ │ │ │
│ │ 例: HttpServletRequest, HttpServletResponse │ │
│ │ Filter, FilterChain │ │
│ │ ServletContextListener │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【Servletコンテナ】= 実行環境(interface の実装者) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servlet API を実装した「動かす側」 │ │
│ │ │ │
│ │ やること: │ │
│ │ ・ポート8080でTCP接続を待ち受け │ │
│ │ ・HTTPリクエストをパース │ │
│ │ ・HttpServletRequest オブジェクトを作成 │ │
│ │ ・適切なServletの service() を呼び出し │ │
│ │ ・レスポンスをHTTPに変換して送信 │ │
│ │ │ │
│ │ 主な実装: Tomcat, Jetty, Undertow, GlassFish │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【Spring Boot】= 高レベルフレームワーク(API の利用者) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servlet API の「上」に構築された便利な層 │ │
│ │ │ │
│ │ やること: │ │
│ │ ・Servletコンテナを内蔵して起動 │ │
│ │ ・DispatcherServlet を登録 │ │
│ │ ・@RestController → Servlet へのブリッジ │ │
│ │ ・JSON変換、例外処理などを自動化 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ リクエスト処理の流れ │
├─────────────────────────────────────────────────────────────┤
│ │
│ ブラウザ: GET /api/users/123 │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servletコンテナ │ │
│ │ ① TCP接続を受け付け │ │
│ │ ② HTTPリクエストをパース │ │
│ │ ③ HttpServletRequest を作成 │ │
│ │ ④ 登録されたServletを呼び出し │ │
│ └───────────────────┬─────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ DispatcherServlet(Spring MVCのServlet) │ │
│ │ ⑤ URLから @RestController を特定 │ │
│ │ ⑥ パスパラメータを抽出 (123) │ │
│ │ ⑦ メソッドを呼び出し │ │
│ └───────────────────┬─────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ @RestController │ │
│ │ ⑧ ビジネスロジック実行 │ │
│ │ ⑨ Userオブジェクトを返却 │ │
│ └───────────────────┬─────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Spring Boot │ │
│ │ ⑩ UserをJSONに変換 │ │
│ │ ⑪ HttpServletResponse に書き込み │ │
│ └───────────────────┬─────────────────────────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servletコンテナ │ │
│ │ ⑫ HTTPレスポンスとして送信 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ブラウザ: {"id": 123, "name": "Alice"} │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 比喩で理解する │
├─────────────────────────────────────────────────────────────┤
│ │
│ レストラン運営に例えると: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servlet API = 「飲食業界の標準マニュアル」 │ │
│ │ ・注文の受け方、料理の出し方のルール │ │
│ │ ・どのレストランチェーンでも共通の「やり方」 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servletコンテナ = 「店舗・設備・スタッフ」 │ │
│ │ ・建物、厨房、ホールスタッフ │ │
│ │ ・お客さんを迎え、注文を受け、料理を運ぶ │ │
│ │ ・標準マニュアル通りに動く │ │
│ │ ・店舗ごとに違う(Tomcat店、Jetty店、Undertow店) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Spring Boot = 「フランチャイズ本部のサポート」 │ │
│ │ ・店舗運営を効率化する仕組み │ │
│ │ ・メニュー管理、在庫管理、会計の自動化 │ │
│ │ ・オーナーは料理(ビジネスロジック)に集中 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ あなたのコード = 「シェフ(料理人)」 │ │
│ │ ・実際に料理を作る人 │ │
│ │ ・店舗運営の細かいことは気にしなくていい │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

なぜServletを学ぶのか

フレームワークの「下」を知る価値

┌─────────────────────────────────────────────────────────────┐
│ Servletを学ぶ理由 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. トラブルシューティング │
│ ┌─────────────────────────────────────────────────┐ │
│ │ エラー発生時、スタックトレースにServletが現れる │ │
│ │ 「DispatcherServlet」「FilterChain」... │ │
│ │ 意味が分かればデバッグが速い │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 2. Spring Bootの内部理解 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ @RestController は DispatcherServlet の上に構築 │ │
│ │ Filterは Spring Security の基盤 │ │
│ │ 「なぜそう動くか」が分かる │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 3. 低レベル操作 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ ファイルダウンロード、ストリーミング │ │
│ │ カスタムヘッダー操作 │ │
│ │ フレームワークが隠蔽している部分を制御 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 4. 他のJVM言語/フレームワークへの応用 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Kotlin + Ktor, Scala + Play も Servlet 上で動く │ │
│ │ 共通の基盤知識として活きる │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

Servletの設計思想

1. リクエスト/レスポンスモデル

┌─────────────────────────────────────────────────────────────┐
│ リクエスト/レスポンスモデル │
├─────────────────────────────────────────────────────────────┤
│ │
│ HTTPの本質をそのままモデル化 │
│ │
│ HTTP: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ GET /users/123 HTTP/1.1 ← リクエスト │ │
│ │ Host: example.com │ │
│ │ Accept: application/json │ │
│ │ │ │
│ │ HTTP/1.1 200 OK ← レスポンス │ │
│ │ Content-Type: application/json │ │
│ │ {"id": 123, "name": "Alice"} │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Servlet: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HttpServletRequest ← リクエストを表すオブジェクト │ │
│ │ ・getMethod() → "GET" │ │
│ │ ・getRequestURI() → "/users/123" │ │
│ │ ・getHeader() → ヘッダー取得 │ │
│ │ │ │
│ │ HttpServletResponse ← レスポンスを表すオブジェクト │ │
│ │ ・setStatus() → ステータスコード設定 │ │
│ │ ・setContentType()→ Content-Type設定 │ │
│ │ ・getWriter() → ボディ書き込み │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 思想: HTTPをオブジェクト指向で表現 │
│ │
└─────────────────────────────────────────────────────────────┘

2. ライフサイクル管理

┌─────────────────────────────────────────────────────────────┐
│ Servletのライフサイクル │
├─────────────────────────────────────────────────────────────┤
│ │
│ コンテナがServletのライフサイクルを管理する │
│ (制御の反転 = IoC) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. ロード コンテナがクラスをロード │ │
│ │ ↓ │ │
│ │ 2. インスタンス化 1つのインスタンスを作成 │ │
│ │ ↓ │ │
│ │ 3. init() 初期化処理(1回だけ) │ │
│ │ ↓ │ │
│ │ 4. service() リクエストごとに呼ばれる │ │
│ │ ↓ (繰り返し) │ │
│ │ 5. destroy() 終了処理(1回だけ) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 重要な特性: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ シングルインスタンス │ │
│ │ ・Servletは1つのインスタンスを複数スレッドで共有 │ │
│ │ ・メモリ効率が良い │ │
│ │ ・しかしスレッドセーフに注意が必要 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Spring Bootとの関連: │
│ ・@PostConstruct = init() に相当 │
│ ・@PreDestroy = destroy() に相当 │
│ ・Beanのスコープ管理も同じ発想 │
│ │
└─────────────────────────────────────────────────────────────┘

3. スレッドモデル

┌─────────────────────────────────────────────────────────────┐
│ Servletのスレッドモデル │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1リクエスト = 1スレッド(Thread-per-Request) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ リクエストA ──→ スレッド1 ──→ Servlet.service() │ │
│ │ リクエストB ──→ スレッド2 ──→ Servlet.service() │ │
│ │ リクエストC ──→ スレッド3 ──→ Servlet.service() │ │
│ │ ↑ │ │
│ │ 同じインスタンス │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 設計上の帰結: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ✅ ローカル変数は安全(スレッドごとに独立) │ │
│ │ ⚠️ インスタンス変数は危険(複数スレッドで共有) │ │
│ │ ⚠️ 静的変数も危険 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ この理解が重要な理由: │
│ ・Spring の @Controller も同じ │
│ ・スレッドセーフでない設計はバグの温床 │
│ ・状態を持たない設計(ステートレス)が基本 │
│ │
└─────────────────────────────────────────────────────────────┘

Servletコンテナの役割

コンテナとは何か

┌─────────────────────────────────────────────────────────────┐
│ Servletコンテナの役割 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Servletコンテナ = Servletの実行環境 │
│ (Webコンテナとも呼ばれる) │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Servletコンテナ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ ネットワーク層 │ │ │
│ │ │ ・ポートのリッスン │ │ │
│ │ │ ・TCP接続の管理 │ │ │
│ │ │ ・HTTPリクエストのパース │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ スレッド管理 │ │ │
│ │ │ ・スレッドプール │ │ │
│ │ │ ・リクエストのディスパッチ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ ライフサイクル管理 │ │ │
│ │ │ ・Servletの初期化/破棄 │ │ │
│ │ │ ・セッション管理 │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ セキュリティ │ │ │
│ │ │ ・認証/認可 │ │ │
│ │ │ ・SSL/TLS │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ あなたが書くのはビジネスロジックだけ │
│ インフラ層はコンテナに任せる │
│ │
└─────────────────────────────────────────────────────────────┘

主要なServletコンテナ

┌─────────────────────────────────────────────────────────────┐
│ 主要なServletコンテナ │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Tomcat │ │
│ │ ・Apache財団が開発 │ │
│ │ ・最も広く使われている │ │
│ │ ・Spring Bootのデフォルト │ │
│ │ ・安定性と実績 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Jetty │ │
│ │ ・Eclipse財団が開発 │ │
│ │ ・軽量、組み込み用途に強い │ │
│ │ ・非同期処理に優れる │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Undertow │ │
│ │ ・Red Hatが開発 │ │
│ │ ・高パフォーマンス │ │
│ │ ・WildFly(JBoss)で使用 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Servlet仕様に準拠していれば、どれでも同じコードが動く │
│ これが「標準仕様」の価値 │
│ │
└─────────────────────────────────────────────────────────────┘

Filter - 横断的関心事の分離

Filterの思想

┌─────────────────────────────────────────────────────────────┐
│ Filterの思想 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 問題: 複数のServletで共通の処理がある │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ UserServlet: │ │
│ │ 認証チェック → ログ出力 → ビジネスロジック │ │
│ │ │ │
│ │ OrderServlet: │ │
│ │ 認証チェック → ログ出力 → ビジネスロジック │ │
│ │ │ │
│ │ ProductServlet: │ │
│ │ 認証チェック → ログ出力 → ビジネスロジック │ │
│ │ │ │
│ │ → 認証チェック、ログ出力が重複! │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 解決: Filterで横断的関心事を分離 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Request → [認証Filter] → [ログFilter] → Servlet │ │
│ │ │ │
│ │ Response ← [認証Filter] ← [ログFilter] ← Servlet │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ・各Servletはビジネスロジックに集中 │
│ ・認証、ログは一箇所で管理 │
│ ・Filterの追加/削除が容易 │
│ │
└─────────────────────────────────────────────────────────────┘

Filterチェーンパターン

┌─────────────────────────────────────────────────────────────┐
│ Filterチェーンパターン │
├─────────────────────────────────────────────────────────────┤
│ │
│ Chain of Responsibility パターンの実装 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Filter1 │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ 前処理 │ │ │
│ │ │ ↓ │ │ │
│ │ │ chain.doFilter() → Filter2 │ │ │
│ │ │ ┌─────────────────────┐ │ │ │
│ │ │ │ 前処理 │ │ │ │
│ │ │ │ ↓ │ │ │ │
│ │ │ │ chain.doFilter() │ │ │ │
│ │ │ │ ↓ │ │ │ │
│ │ │ │ Servlet │ │ │ │
│ │ │ │ ↓ │ │ │ │
│ │ │ │ 後処理 │ │ │ │
│ │ │ └─────────────────────┘ │ │ │
│ │ │ ↓ │ │ │
│ │ │ 後処理 │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ このパターンは多くの場所で使われている: │
│ ・Spring Security のフィルターチェーン │
│ ・Express.js のミドルウェア │
│ ・Go の HTTP ミドルウェア │
│ │
└─────────────────────────────────────────────────────────────┘

よくあるFilterの用途

┌─────────────────────────────────────────────────────────────┐
│ Filterの典型的な用途 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 認証/認可 │ │
│ │ ・トークン検証 │ │
│ │ ・アクセス制御 │ │
│ │ → Spring Security の核心 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ロギング │ │
│ │ ・リクエスト/レスポンスの記録 │ │
│ │ ・処理時間の計測 │ │
│ │ → 監査ログ、デバッグ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ CORS(Cross-Origin Resource Sharing) │ │
│ │ ・適切なヘッダーの付与 │ │
│ │ → SPAとの連携に必須 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 圧縮 │ │
│ │ ・レスポンスのgzip圧縮 │ │
│ │ → 帯域幅の節約 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 文字エンコーディング │ │
│ │ ・リクエスト/レスポンスのエンコーディング設定 │ │
│ │ → 文字化け防止 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘

Listener - イベント駆動設計

Listenerの思想

┌─────────────────────────────────────────────────────────────┐
│ Listenerの思想 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Observer パターン: イベントを監視して反応 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ イベント発生源 Listener │ │
│ │ ┌──────────┐ ┌──────────┐ │ │
│ │ │ │ ──通知──→ │ │ │ │
│ │ │ コンテナ │ │ 処理実行 │ │ │
│ │ │ │ │ │ │ │
│ │ └──────────┘ └──────────┘ │ │
│ │ │ │
│ │ 「何かが起きたら教えて」という設計 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 監視できるイベント: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ServletContextListener │ │
│ │ ・アプリケーションの起動/終了 │ │
│ │ ・初期化処理、クリーンアップ │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HttpSessionListener │ │
│ │ ・セッションの作成/破棄 │ │
│ │ ・アクティブセッション数の監視 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ServletRequestListener │ │
│ │ ・リクエストの開始/終了 │ │
│ │ ・リクエストスコープの管理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Spring Bootとの関連: │
│ ・@EventListener も同じ発想 │
│ ・ApplicationEvent でカスタムイベントを定義可能 │
│ │
└─────────────────────────────────────────────────────────────┘

ServletとSpring MVCの関係

DispatcherServlet

┌─────────────────────────────────────────────────────────────┐
│ DispatcherServlet │
├─────────────────────────────────────────────────────────────┤
│ │
│ Spring MVCの中心 = 特別なServlet │
│ 「フロントコントローラー」パターン │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 従来のServlet: │ │
│ │ /users → UserServlet │ │
│ │ /orders → OrderServlet │ │
│ │ /products→ ProductServlet │ │
│ │ (URLごとにServletを作る) │ │
│ │ │ │
│ │ DispatcherServlet: │ │
│ │ /* → DispatcherServlet │ │
│ │ ↓ │ │
│ │ 適切な@Controllerにルーティング │ │
│ │ (1つのServletが全てを受け、振り分ける) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ この設計のメリット: │
│ ・共通処理を一箇所に集約 │
│ ・URLとハンドラーの柔軟なマッピング │
│ ・インターセプター、例外ハンドラーの統一管理 │
│ │
└─────────────────────────────────────────────────────────────┘

リクエスト処理の流れ

┌─────────────────────────────────────────────────────────────┐
│ Spring MVCのリクエスト処理 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ HTTP Request │ │
│ │ ↓ │ │
│ │ Servletコンテナ(Tomcat) │ │
│ │ ↓ │ │
│ │ Filter チェーン(CORS, Security, Logging...) │ │
│ │ ↓ │ │
│ │ DispatcherServlet(フロントコントローラー) │ │
│ │ ↓ │ │
│ │ HandlerMapping(URLから@Controllerを特定) │ │
│ │ ↓ │ │
│ │ HandlerAdapter(メソッド呼び出しを適応) │ │
│ │ ↓ │ │
│ │ @Controller / @RestController │ │
│ │ ↓ │ │
│ │ HttpMessageConverter(JSON変換等) │ │
│ │ ↓ │ │
│ │ HTTP Response │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 各層が単一責任を持つ │
│ Servlet APIはこの土台となっている │
│ │
└─────────────────────────────────────────────────────────────┘

まとめ

Servletの設計思想

思想説明
リクエスト/レスポンスモデルHTTPをオブジェクト指向で表現
ライフサイクル管理コンテナがインスタンスを管理(IoC)
スレッドモデル1リクエスト=1スレッド、シングルインスタンス
横断的関心事の分離Filterによる共通処理の分離
イベント駆動Listenerによるイベント監視

理解すべきこと

┌─────────────────────────────────────────────────────────────┐
│ Servletを学んで得られること │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Webアプリケーションの「土台」がわかる │
│ ・Spring Boot の「下」で何が起きているか │
│ ・なぜ @RestController で HTTP が処理できるか │
│ │
│ 2. デザインパターンの実例 │
│ ・フロントコントローラー(DispatcherServlet) │
│ ・Chain of Responsibility(Filter) │
│ ・Observer(Listener) │
│ │
│ 3. トラブルシューティング能力 │
│ ・スタックトレースが読める │
│ ・「なぜ動かないか」の推論ができる │
│ │
│ 4. 設計判断の根拠 │
│ ・いつフレームワークを使い、いつ使わないか │
│ ・抽象化のレイヤーを選べる │
│ │
└─────────────────────────────────────────────────────────────┘

次のステップ