【Java & Tomcat】サーブレットのライフサイクル ※サンプルプログラム付き

  • このエントリーをはてなブックマークに追加
  • Pocket

この記事ではサーブレットのライフサイクルについて説明する。

ライフサイクルとは何か

サーブレット(Servlet)のライフサイクル(Servlet Life Cycle)とは、Webコンテナの中でサーブレットが生成されてから消去されるまでの過程である。サーブレットはJavaのクラスがそうであるようにインスタンスが生成され、そのインスタンスが要求されたサービスを実行する。そして、必要なくなったときに削除される。この過程がサーブレットのライフサイクルである。

この図は、サーブレットのライフサイクルを表したものである。

その詳細をはじまりから見てみよう。

はじまり

Javaで書かれたコードがコンパイルされてクラスファイルになる。そして、Webコンテナに配置されたところからサーブレットのライフサイクルが始まる。Webコンテナに配置されたサーブレットは、Webコンテナによってコントロールされる。そして、リクエストがサーブレットに割り当てられた時、Webコンテナは次のステップを実行する。

ステップ1:インスタンスの生成と初期化

もし、サーブレットのインスタンスが存在しなかったなら、Webコンテナは

  1. Servletクラスをロードする。
  2. Servletクラスのインスタンスを生成する。
  3. サーブレットのinit()メソッドを呼び出すことにより、サーブレットのインスタンスを初期化する。

ステップ2:リクエストによるサービスメソッド呼び出し

Webコンテナは、リクエストとレスポンス・オブジェクトを引数として渡すservive()メソッドを起動する。

インスタンスの削除:destroy()メソッド

もしインスタンスを削除することが必要であれば、Webコンテナはdestroy()メソッドを呼び出すことによりサーブレットを終了させる。

ライフサイクルイベント

サーブレットにはライフサイクルイベントを活用する仕組みがあり、サーブレットの状態を知ることができる。ライフサイクルイベントが発生した時、リスナーオブジェクトに呼び出されるメソッドを定義することによって、イベントをモニターしたり、対応した処理をしたりすることができる。

ライフサイクルイベントして活用できる主なものを以下に示す。コンテキストとは、実行情報のことである。

オブジェクト

イベントの詳細

Webコンテキスト

イベント:初期化と消滅。

Webアプリケーションのサーブレットコンテキスト(実行)の変化について通知するためのイベントである。

リスナークラス:javax.servlet.ServletContextListener
イベントクラス:javax.servlet.ServletContextEvent

セッション

イベント:生成、無効、有効、パッシベーション、タイムアウト

Webアプリケーション内のセッションの変化について通知するためのイベントである。

リスナークラス:
javax.servlet.http.HttpSessionListener, javax.servlet.http.HttpSessionActivationListener,

イベントクラス:
javax.servlet.http.HttpSessionEvent

リクエスト

イベント:サーブレトリクエストがWebコンポーネントによって処理されることが始まった。

 

リスナークラス:javax.servlet.ServletRequestListener

イベントクラス:javax.servlet. ServletRequestEvent

どのように活用できるのかを、サンプルプログラムで見てみよう。

ServletContextListenerの仕様

ServletContextListenerクラスにある二つのメソッドのAPI仕様を示す。

contextInitialized(ServletContextEvent sce)

戻り値の型

void

内容

ウェブアプリケーションの初期化のプロセスが始まっている通知である。すべてのサーブレットコンテキストのリスナーは、Webアプリケーションのどんなフィルターもしくはサーブレットでも、初期化される前にコンテキストの初期化を知らされている。

引数:
sce -初期化された サーブレットコンテキストについての情報

contextDestroyed(ServletContextEvent sce)

戻り値の型

void

内容

サーブレットコンテキストがシャットダウンされようとしている通知である。サーブレットコンテキストリスナーがコンテキストの破壊について知らされる前に、すべてのサーブレットとフィルターは破壊されてしまっている。

引数:sce - 破壊されたサーブレットコンテキストについての情報

HttpSessionListenerの仕様

HttpSessionListenerクラスにある二つのメソッドのAPI仕様を示す。

sessionCreated(HttpSessionEvent se)

戻り値の型

void

内容

セッションが生成されたことを通知。

引数:se – 通知イベント。

sessionDestroyed(HttpSessionEvent se)

戻り値の型

void

内容

セッションが無効になることを通知。

引数:se – 通知イベント。

ServletRequestListenerの仕様

ServletRequestListenerクラスにある二つのメソッドのAPI仕様を示す。

sessionCreated(HttpSessionEvent se)

戻り値の型

void

内容

Webアプリケーションのスコープから入ることを通知。

引数:sre – リクエストについての情報。

requestDestroyed(ServletRequestEvent sre)

戻り値の型

void

内容

Webアプリケーションのスコープから出ることを通知。

引数:sre – リクエストについての情報。

 

コンテキストイベントのサンプルプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。このサンプルプログラムでは、コンテキストイベントをListenerクラスで受け取っている。その結果はログとして出力される。

このサンプルプログラムを実行させるために、Webサーバーを起動し、しばらく待ってWebサーバーを終了している。この手順で、下記の実行結果が得られる。

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener()//[1]
public class ContextEventListener  implements ServletContextListener {//[2]
    public void contextInitialized(ServletContextEvent event) {//[3]
        ServletContext context = event.getServletContext();//[4]
        context.log("[5]コンテキスト:開始");
    }
    public void contextDestroyed(ServletContextEvent event) {//[6]
        ServletContext context = event.getServletContext();//[7]
        context.log("コンテキスト:終了");//[8]
    }
}

実行結果

1 07, 2017 11:41:21 午後 org.apache.catalina.core.ApplicationContext log
情報: [5] コンテキスト:開始
1 07, 2017 11:41:29 午後 org.apache.catalina.core.ApplicationContext log
情報: [8] コンテキスト:終了

 

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] ServletContextListenerを継承して、ContextEventListenerクラスを提起する。
  • [3] 修飾子publicでメソッドcontextInitialized ()を宣言する。
  • [4] eventオブジェクトからコンテキストを取得する。
  • [5] 「コンテキスト:開始」をコンテキストのログに出力する。
  • [6] 修飾子publicでメソッドcontextDestroyed ()を宣言する。
  • [7] eventオブジェクトからコンテキストを取得する。
  • [8] 「コンテキスト:終了」をコンテキストのログに出力する。

セッションイベントのサンプルプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent ;
import javax.servlet.http.HttpSessionListener;

@WebListener()//[1]
public class SessionEventListener  implements HttpSessionListener {//[2]
    public void sessionCreated(HttpSessionEvent  event) {//[3]
               HttpSession session = event.getSession();//[4]
        ServletContext context = session.getServletContext();//[5]
        context.log("[6] セッション開始: ID = " + session.getId());
    }
    public void sessionDestroyed(HttpSessionEvent event) {//[7]
               HttpSession session = event.getSession();//[8]
        ServletContext context = session.getServletContext();//[9]
        context.log("[10] セッション終了:ID = " + session.getId());
    }
}

実行結果

1 09, 2017 9:55:57 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] セッション開始: ID = DF2FA0C602123211CF6FE75860B5836E
1 09, 2017 9:55:58 午前 org.apache.catalina.core.ApplicationContext log
情報: [10] セッション終了:ID = DF2FA0C602123211CF6FE75860B5836E

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpSessionListenerを継承して、SessionEventListenerクラスを定義する。
  • [3] 修飾子publicでメソッドsessionCreated ()を宣言する。
  • [4] eventオブジェクトからセッションを取得する。
  • [5] sessionオブジェクトからコンテキストを取得する。
  • [6] 「セッション開始: ID =(セッションIDを取得)」をコンテキストのログに出力する。
  • [7] 修飾子publicでメソッドsessionDestroyed ()を宣言する。
  • [8] eventオブジェクトからリクエストを取得する。
  • [9] eventオブジェクトからコンテキストを取得する。
  • [10] 「セッション終了: ID =(セッションIDを取得)」をコンテキストのログに出力する。

リクエストイベントのサンプルプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。

import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;

@WebListener()//[1]
public class RequestEventListener  implements ServletRequestListener {//[2]
    public void requestInitialized(ServletRequestEvent event) {//[3]
        ServletRequest request = event.getServletRequest();//[4]
        ServletContext context = event.getServletContext();//[5]
        context.log("[6] " + request.getRemoteAddr() + "のリクエストがスコープに入る");
    }
    public void requestDestroyed(ServletRequestEvent event) {//[7]
        ServletRequest request = event.getServletRequest();//[8]
        ServletContext context = event.getServletContext();//[9]
        context.log("[10] " + request.getRemoteAddr() + "のリクエストがスコープから出る");
    }
}

実行結果

1 08, 2017 1:26:16 午後 org.apache.catalina.core.ApplicationContext log
情報: [6] 0:0:0:0:0:0:0:1のリクエストがスコープに入る
1 08, 2017 1:26:16 午後 org.apache.catalina.core.ApplicationContext log
情報: [10] 0:0:0:0:0:0:0:1のリクエストがスコープから出る

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] ServletRequestListenerを継承して、RequestEventListenerクラスを定義する。
  • [3] 修飾子publicでメソッドrequestInitialized ()を宣言する。
  • [4] eventオブジェクトからリクエストを取得する。
  • [5] eventオブジェクトからコンテキストを取得する。
  • [6] 「(リクエストを出したクライアントのアドレス)のリクエストがスコープに入る」をコンテキストのログに出力する。
  • [7] 修飾子publicでメソッドrequestDestroyed ()を宣言する。
  • [8] eventオブジェクトからリクエストを取得する。
  • [9] eventオブジェクトからコンテキストを取得する。
  • [10] 「(リクエストを出したクライアントのアドレス)のリクエストがスコープから出る」をコンテキストのログに出力する。

イベント発生させたサーブレットプログラム

ライフサイクルイベントを受け取るためには、ListenerクラスにListenerインターフェースを実装することによって定義できる。

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

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/EventTest")//[1]
public class ServleEventTest extends HttpServlet {//[2]
                   public void init() throws ServletException{//[3]
                                     log("[4] init()");
                   }
                   protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                                        throws ServletException, IOException {//[5]
                                     PrintWriter out = response.getWriter();//[6]
                                     out.write("[7] Event Test Servlet => ");
                                    
                                     HttpSession session = request.getSession(false);//[8]
                                     if (session == null){//[9]
                                                        session = request.getSession(true);//[10]
                                                        out.write("[11] Session has started");
                                                        return;//[12]
                                     }
                                     out.write("[13] Session has closed");
                                     session.invalidate();//[14]
                   }
                   public void destroy(){//[15]
                                     log("[16] destroy()");
                   }
}

実行結果

手順1)Webサーバーを起動する。

ログ:

1 09, 2017 11:13:04 午前 org.apache.catalina.core.StandardService startInternal
情報: サービス Catalina を起動します
1 09, 2017 11:13:04 午前 org.apache.catalina.core.StandardEngine startInternal
情報: Starting Servlet Engine: Apache Tomcat/7.0.73
1 09, 2017 11:13:05 午前 org.apache.catalina.core.ApplicationContext log
情報: [5] コンテキスト:開始

手順2)ブラウザにURL: http://localhost:8080/Servlet/EventTest と入力し、Enterを押す。

ブラウザ画面:

ログ:

1 09, 2017 11:13:14 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] 0:0:0:0:0:0:0:1のリクエストがスコープに入る
1 09, 2017 11:13:14 午前 org.apache.catalina.core.ApplicationContext log
情報: lifecycleevent.ServleEventTest: [4] init()
1 09, 2017 11:13:14 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] セッション開始: ID = A30AA242438DEE29A6B075B366BEC09B

手順3)ブラウザの更新ボタンを押す。

ブラウザ画面:

ログ:

1 09, 2017 11:15:08 午前 org.apache.catalina.core.ApplicationContext log
情報: [6] 0:0:0:0:0:0:0:1のリクエストがスコープに入る
1 09, 2017 11:15:08 午前 org.apache.catalina.core.ApplicationContext log
情報: [10] セッション終了:ID = A30AA242438DEE29A6B075B366BEC09B
1 09, 2017 11:15:08 午前 org.apache.catalina.core.ApplicationContext log
情報: [10] 0:0:0:0:0:0:0:1のリクエストがスコープから出る

手順4)Webサーバーを停止する。

ログ:

1 09, 2017 11:16:01 午前 org.apache.catalina.core.StandardService stopInternal
情報: サービス Catalina を停止します
1 09, 2017 11:16:01 午前 org.apache.catalina.core.ApplicationContext log
情報: lifecycleevent.ServleEventTest: [16] destroy()
1 09, 2017 11:16:01 午前 org.apache.catalina.core.ApplicationContext log
情報: [8] コンテキスト:終了

サンプルプログラムの説明

それでは簡単にプログラムの解説をしてゆこう。

  • [1] アノテーションの宣言をする。
  • [2] HttpServletを継承して、ServleEventTestクラスを定義する。
  • [3] 修飾子publicでメソッドServletException ()を宣言する。
  • [4] 「init()」をコンテキストのログに出力する。
  • [5] 修飾子publicでメソッドdoGet ()をオーバーライドする。
  • [6] HTMLを出力するためのoutオブジェクトを取得する。
  • [7] outオブジェクトに「Event Test Servlet => 」を出力する。
  • [8] セッションsessionオブジェクトを取得する。
  • [9][10] セッションが開始されていない時、セッションを開始する。
  • [11][12] outオブジェクトに「Session has started」を出力し、処理を終了する。
  • [13] outオブジェクトに「Session has closed」を出力する。
  • [14] セッションを終了する。

ライフサイクルの詳細

サーブレットの生成と初期化

@WebServletアノテーションを使ってWebアプリケーションのサーブレット・コンポーネントの定義を行う。このアノテーションはクラスの仕様に含められ、宣言されたサーブレットについての属性情報を含んでいる。アノテーションが付いているサーブレットは少なくともひとつのURLパターンを属性情報として含んでいなければならない。これは、アノテーションのurlPatternsまたはvalue 属性によって特定される。他の全ての属性はオプションで、指定されなければデフォルト設定となる。アノテーションの属性がURLパターンの時だけは、value属性を使用してください。他方、他の属性が使われている時は、urlPatternsを使用してください。

例えば、次のコードの抜粋は、URLパターン「/report」を持つサーブレットを定義する。@WebServletでアノテーションを付加されたクラスはjavax.servlet.http.HttpServletを継承していなければならない。

@WebServlet("/report")public class MoodServlet extends HttpServlet {    ...

Webコンテナは、サーブレットクラスがローディグされ初期化された後、クライアントから送られたリクエストが来る前に初期化しなければならない。永続的な構成データを読むこと、リソースを初期化すること、その他の一度だけのアクティビティを実行することをサーブレットに許可してこのプロセスをカスタマイズするために、サーブレットのinit()メソッドをオーバーライドするか、@WebServletアノテーションのinitParams属性を指定することができる。initParams属性は、@WebInitParamアノテーションを含んでいる。もし初期化プロセスを完了できない時は、サーブレットはUnavailableException例外を発生させる。特定のサーブレットによって必要とされるデータを提供するために初期化パラメータを使用してください。対照的に、コンテキスト属性はWebアプリケーションのすべてのコンポーネントに有効なデータを提供する。

サービスメソッド

サーブレットによって提供されるサービスは、GenericServletのserviceメソッドの中、httpServletオブジェクトのdoMethods(Methodの部分は、Get, Delete, Options, Post, Put, or Trace置き換えられる)の中、またはサーブレットインターフェースを実装したクラスによって定義された他のプロトコルに依存したメソッドの中に実装したものである。serviceメソッドという言葉は、クライアントにサービスを提供するサーブレットクラスの中にあるどんなメソッドのために使われる。

サービス(serviceメソッドのための一般的なパターンは、リクエストから情報を抽出すること、そしてその情報に基づいて外部リソースにアクセスすること、そしてレスポンスに反映させる。HTTPサーブレットのために、レスポンスに反映させるための正しい手順は、次の通りです。

  1. レスポンスから出力ストリームを取り出す。
  2. レスポンスヘッダーに書き込む。
  3. 出力ストリームにすべてのコンテンツ本体を書き込む。

レスポンスがコミットされる前に、レスポンスヘッダーは設定されなければならない。レスポンスがコミットされた後に設定または追加されたどんな試みも、Webコンテナは無視する。

まとめ

この記事では、サーブレットのライフサイクルについて紹介した。サンプルプログラムを実際に動作させるなどして、仕組みを理解しよう。

 

  • このエントリーをはてなブックマークに追加
  • Pocket

このページの続きや関連ページは下記から一覧で確認できます。

IT講師に興味はありませんか?

・「今までIT講師をやってきたが、更に多くの講義を行いたい」

・「エンジニアとしてやってきたが講師業に魅力を感じている」

・「講師として活躍するためにベースとなる知識を知りたい」

・「様々な分野や言語の講師にチャレンジしてみたい」


という方はぜひIT講師募集のページをご覧ください。


リスキルテクノロジーでは「受講している方々にITを好きになってもらう」ことを目標に、同じ目標に向かって歩んで行ける講師の方を常に探しています。


システム開発やインフラ構築などのエンジニアリング経験を活かし、新入社員などの未経験者や経験の浅い初学者の方々に対してITトレーニングを行っていただくことになります。


テキストやカリキュラムは事前に用意されており、それらを元に講義を進めていくため、IT講師をはじめて実施する方でも安心してトレーニングを実施できます。


IT講師募集のページを見る

SNSでもご購読できます。

コメントを残す

*

未経験からの育成制度も充実
IT講師に興味はありませんか?

リスキルテクノロジーでIT講師の積極募集を開始! 経験・未経験問わずご応募可能。育成制度で講師スキル向上も目指せます

IT講師に応募する