Servletコンテナ
Servlet APIが「契約(interface)」なら、Servletコンテナはその「実装者」です。Servletコンテナを理解することで、Webアプリケーションがどのように動いているかの全体像が見えてきます。
Servletコンテナとは
役割
┌─────────────────────────────────────────────────────────────┐
│ Servletコンテナの役割 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Servletコンテナ = Servlet API の実装 + 実行環境 │
│ │
│ 2つの顔を持つ: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. Servlet API の実装者 │ │
│ │ ・HttpServletRequest を実装したクラスを提供 │ │
│ │ ・HttpServletResponse を実装したクラスを提供 │ │
│ │ ・Filter, Listener の仕組みを提供 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 2. Webサーバーとしての実行環境 │ │
│ │ ・HTTPリクエストを受信 │ │
│ │ ・スレッドを割り当て │ │
│ │ ・Servletを呼び出し │ │
│ │ ・HTTPレスポンスを送信 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
なぜコンテナが必要か
┌─────────────────────────────────────────────────────────────┐
│ コンテナなしで作ると... │
├─────────────────────────────────────────────────────────────┤
│ │
│ 自分で全部実装する必要がある: │
│ │
│ □ TCPソケットのリッスン │
│ □ 複数接続の同時処理(スレッドプール) │
│ □ HTTPリクエストのパース │
│ ・リクエストライン解析 │
│ ・ヘッダー解析 │
│ ・ボディ解析(multipart, chunked等) │
│ □ Keep-Alive接続の管理 │
│ □ HTTPレスポンスの構築 │
│ □ SSL/TLS対応 │
│ □ セッション管理 │
│ □ 仮想ホスト 対応 │
│ □ アクセスログ出力 │
│ □ ... │
│ │
│ → 本来作りたいビジネスロジックに集中できない │
│ → 車輪の再発明 │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ コンテナがあると... │
├─────────────────────────────────────────────────────────────┤
│ │
│ インフラ層はコンテナに任せる: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ あなたが書くこと │ │
│ │ ・doGet() の中身(ビジネスロジック) │ │
│ │ ・それだけ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ コンテナがやること │ │
│ │ ・HTTP通信の全て │ │
│ │ ・スレッド管理の全て │ │
│ │ ・セキュリティの基盤 │ │
│ │ ・セッション管理 │ │
│ │ ・ログ出力 │ │
│ └──────────────────── ─────────────────────────────────┘ │
│ │
│ → 関心の分離(Separation of Concerns) │
│ │
└─────────────────────────────────────────────────────────────┘
コンテナの責務
1. ネットワーク層
┌─────────────────────────────────────────────────────────────┐
│ ネットワーク層の責務 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【TCP接続管理】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・ポート(通常8080)でリッスン │ │
│ │ ・接続の受け入れ(accept) │ │
│ │ ・Keep-Aliveの管理 │ │
│ │ ・接続タイムアウト処理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【HTTPパース】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ バイト列 → HTTPリクエストオブジェクト │ │
│ │ │ │
│ │ "GET /users?id=1 HTTP/1.1\r\n" │ │
│ │ "Host: example.com\r\n" │ │
│ │ "Accept: application/json\r\n" │ │
│ │ "\r\n" │ │
│ │ ↓ パース │ │
│ │ HttpServletRequest オブジェクト │ │
│ │ method: "GET" │ │
│ │ uri: "/users" │ │
│ │ parameters: {id: "1"} │ │
│ │ headers: {Host: "...", Accept: "..."} │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【HTTPレスポンス構築】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HttpServletResponse オブジェクト → バイト列 │ │
│ │ │ │
│ │ status: 200 │ │
│ │ contentType: "application/json" │ │
│ │ body: {"name": "Alice"} │ │
│ │ ↓ 構築 │ │
│ │ "HTTP/1.1 200 OK\r\n" │ │
│ │ "Content-Type: application/json\r\n" │ │
│ │ "Content-Length: 17\r\n" │ │
│ │ "\r\n" │ │
│ │ "{\"name\":\"Alice\"}" │ │
│ └───────────────────────── ────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
2. スレッド管理
┌─────────────────────────────────────────────────────────────┐
│ スレッド管理の責務 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【スレッドプール】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ リクエスト1 ─→ ワーカースレッド1 ─→ Servlet │ │
│ │ リクエスト2 ─→ ワーカースレッド2 ─→ Servlet │ │
│ │ リクエスト3 ─→ ワーカースレッド3 ─→ Servlet │ │
│ │ リクエスト4 ─→ (待機中...) │ │
│ │ ↑ │ │
│ │ スレッドプール │ │
│ │ (例: 最大200スレッド) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ なぜスレッドプール? │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・スレッド生成コストの削減(再利用) │ │
│ │ ・リソース枯渇の防止(上限設定) │ │
│ │ ・過負荷時のグレースフルな処理 │ │
│ └───────── ────────────────────────────────────────────┘ │
│ │
│ 【設定可能なパラメータ】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・最小スレッド数(アイドル時も維持) │ │
│ │ ・最大スレッド数(これ以上は作らない) │ │
│ │ ・キュー長(最大スレッド使用中の待機数) │ │
│ │ ・タイムアウト(アイドルスレッドの破棄) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────── ──────────────────────────────────────────┘
3. ライフサイクル管理
┌─────────────────────────────────────────────────────────────┐
│ ライフサイクル管理の責務 │
├─────────────────────────────────────── ──────────────────────┤
│ │
│ コンテナがServletの生死を管理する(IoC) │
│ │
│ 【起動時】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. Servletクラスをロード │ │
│ │ 2. インスタンスを1つ作成 │ │
│ │ 3. init() を呼び出し │ │
│ │ 4. リクエスト受付開始 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【リクエスト時】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. スレッドプールからスレッドを取得 │ │
│ │ 2. HttpServletRequest/Response を作成 │ │
│ │ 3. Servlet.service() を呼び出し │ │
│ │ 4. スレッドをプールに返却 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【終了時】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 新規リクエストの受付停止 │ │
│ │ 2. 処理中リクエストの完了を待機 │ │
│ │ 3. destroy() を呼び出し │ │
│ │ 4. リソース解放 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ グレースフルシャットダウン: │
│ ・処理中のリクエストを中断せず完了させる │
│ ・コンテナがこれを保証する │
│ │
└─────────────────────────────────────────────────────────────┘
4. セッション管理
┌─────────────────────────────────────────────────────────────┐
│ セッション管理の責務 │
├─────────────────────────────────────────────────────────────┤
│ │
│ HTTPはステートレス → コンテナがステートを管理 │
│ │
│ 【仕組み】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ブラウザ コンテナ │ │
│ │ │ │ │ │
│ │ │ ─── 初回リクエスト ───→ │ │ │
│ │ │ │ セッション作成 │ │
│ │ │ │ ID: abc123 │ │
│ │ │ ←── Set-Cookie ──────── │ │ │
│ │ │ JSESSIONID=abc123 │ │ │
│ │ │ │ │ │
│ │ │ ─── 2回目リクエスト ──→ │ │ │
│ │ │ Cookie: JSESSIONID │ セッション取得 │ │
│ │ │ │ ID: abc123 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【コンテナの責務】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・セッションIDの生成(ランダム、推 測困難) │ │
│ │ ・Cookieの送受信 │ │
│ │ ・セッションオブジェクトの保存(メモリ/永続化) │ │
│ │ ・タイムアウト管理(期限切れセッションの破棄) │ │
│ │ ・クラスタ環境でのセッション共有(設定次第) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
5. セキュリティ
┌─────────────────────────────────────────────────────────────┐
│ セキュリティの責務 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【SSL/TLS】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・HTTPS接続の終端 │ │
│ │ ・証明書の管理 │ │
│ │ ・暗号化/復号化 │ │
│ │ ・プロトコルバージョン制御(TLS 1.2/1.3) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 【基本認証】 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ・BASIC認証の処理 │ │
│ │ ・DIGEST認証の処理 │ │
│ │ ・レルム(認証領域)の管理 │ │