重点用語解説

サーバサイドJavaテクノロジ 重点キーワード

米持幸寿
日本アイ・ビー・エム
2000/10/10

 

Java Servlet


サーブレットの生い立ち

 Java Servlet は、Webサーバ、つまりはHTTPサーバを、アプリケーション・サーバに変身させるJavaテクノロジである。そのため、Java Servlet必ずといってよいほど CGI と比較される。

 現在でも、かなりのWebプログラマが、Perl/CGIによるアプリケーション開発を行っている。筆者の周りでも、Webアプリケーション開発のプロジェクトが始まってから十分な人数のJavaログラマが見つからず、「CGI なら慣れているから」という理由で、 CGI開発を進めるケースが今でも見受けられる。

 CGIは、UNIXログラマにとって非常に分かりやすい構造だった。CGI プログラムは、UNIXでいうところのいわゆる「フィルタ・プログラム=パイプ・プログラム」だからである。CGIプログラムは、基本的に1つのプロセスで動作する。入力として環境変数(GET方式/PUT方式)または標準入力(PUT方式)を使い、結果として標準出力を使うという点は、UNIX プログラマにとって非常に受け入れられやすい。また、コマンドプロンプトを使って動作確認もできるので、非常に便利だ。また、開発言語が UNIXプログラマには馴染みの深いPerl であることも理由の1つであろう。

 Java ServletとCGIの違いについて理解するために、まずはCGIについて簡単に説明しよう。まず、図1はクライアントからのリクエストがCGIに対してのものではなかった場合のサーバ側の動作を説明している。

図1 クライアントからのリクエストがCGIでなかった場合

 次の図2が、クライアントからのリクエストがCGIに対してのものだった場合のサーバ側の動作である。

図2 クライアントからのリクエストがCGIだった場合

 しかしながらCGIには欠点があるといわれている。それは主に次のようなことである。

  1. プロセス起動のためパフォーマンスが悪い
  2. ステートレスである
  3. コンピュータの機種によってPerlの互換性がない

Java Servletではこれらを克服している。

Java Servletの開発手順

 Java Servletは、ユーザー・プログラムを作成するときに、Http Servletクラスを継承したクラスを作成する。ここでは、便宜上これをユーザー・サーブレットと呼ぶことにする。これは、Java Appletと同じような思想だ。オブジェクト指向では当たり前のやり方であるが、オブジェクト指向が身に付いていない人には分かりにくいだろう。

 ユーザー・サーブレットは、サーバ・プロセスである「サーブレット・エンジン」に、ユーザー・クラスとしてロードされ、基本的には1つの共通インスタンスを生成する。サーブレット・エンジンはそれ自身がJavaのプログラムである。該当サーブレットに対するHTTPリクエストは、このインスタンスに対してのスレッドとしてリダイレクトされる。これによって、HTTPリクエストの処理がユーザー・プログラムによって処理され、結果がブラウザに送られる(図3)

図3 Java Servletでは、ユーザー・サーブレットがサーブレット・エンジンにクラスとしてロードされ、1つのインスタンスを生成する。クライアントからのHTTPリクエストがあると、インスタンスからスレッドが起動され処理が行われる。処理結果はブラウザに送られる

 この方法だと、プロセスの起動や終了処理がなく、スレッドであるため高速で、使用するリソースも少ない。さらに、インスタンスは1度ロードされるとメモリ上に維持されるため、アプリケーションの状態を維持することも可能である。これによりステートフルな技術であるといわれている。さらに、Javaであることから、非常に高い移植性を発揮する。

 サーバ・プロセスであるサーブレット・エンジンがユーザー・サーブレットを呼び出すルールは、基本的に次の順序で行われる。

  1. リクエストに対するサービス・メソッドが定義されているか確認する。例えば、GETリクエストに対してはdoGetメソッド、POSTに対してはdoPostメソッド、である
  2. doXXXメソッドが1つでも定義されており、リクエストに合致するメソッドが提供されていないとき、このリクエストはそのServletによって処理できないことを意味する。例えば、doPostメソッドはあるが、doGetメソッドのないServletを作った場合、そのServletはURL指定や <A HREF=> タグによって直接参照することはできない。必ずフォームを作成して呼び出す必要がある
  3. doXXXメソッドが1つもなく、serviceメソッドがあれば、それが呼ばれる

 ユーザー・サーブレットはサーバに呼び込まれたとき、インスタンスを生成し、そのインスタンスが共通に使われることになる。共通に使われるため、スレッド間で共有できるようなものはインスタンス生成時に初期化しておきたい。これを行うためには、initメソッドを使う。これもAppletに似ているので、分かりやすいだろう。initメソッドには、ServletConfigオブジェクトが渡されることになっており、このデータを使ってサーブレットに外部データを簡単に渡すことができる。例えば、RDBにアクセスするときのJDBC-URLなどをここで渡す。ServletConfig は、サーブレットのクラスファイルと同じディレクトリにクラス名.servletというファイル名でXML形式にて置く。また、終了処理も当然ながら必要だが、これはdestroyメソッドで行う。

 以上を総括すると、サーブレット・プログラムの開発(コーディング)手順は以下のようにまとめられる。

  1. HttpServlet を継承したクラスを作成する
  2. 必要に応じて init、destroy メソッドを記述する(パラメータは決まっている)
  3. 必要に応じて service、doGet、doPost といったメソッドを記述する(パラメータや例外は決まっている)
  4. コンパイルし、サーバの定められたクラスパス上に置く

リスト1 もっとも簡単なサーブレットソース

import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.*;
public class EasyServlet extends

HttpServlet {
 public void init( ServletConfig config ) throws  ServletException {
  super.init( config ); // ここで、必要に応じて初期化処理
 }

public void destroy() {
  super.destroy(); // ここで、必要に応じて終了処理
 }
 

public void service( HttpServletRequest req,  HttpServletResponse resp )
 throws ServletException, IOException {
  PrintWriter out = resp.getWriter();
  out.println( "<HTML>" );
  out.println( " <BODY>" );
  out.println( " <H1>カンタンなサーブレット!</H1>" );
  out.println( " </BODY>" );
  out.println( "</HTML>" );
 }
}


セッション管理

 JavaServlet にはセッション管理機能が備えられている。本当の意味で、サーブレットのステートフルを支えているのは、このセッション管理機能である。JavaServlet の仕様は、Sun MicrosystemsのJavaWebServer(JWS)で提供され、その後分離した仕様として公開されたあと、J2EE ( Java2 Enterprise Edition)に吸収された。セッション管理はWS 1.1 alpha時代から追加された考え方であり、システム(サーブレット・エンジン)がこの管理を行う。基本的な考え方は以下のようなものである。

 HTTPリクエストは、基本的にセッションレスである。1回のリクエスト/レスポンスでセッションが終了し、それ以降は関係が維持されない。そのため、複数の画面で構成されるようなアプリケーションを開発するとき、それぞれの画面での持続性を維持する機能をHTTPリクエストより上層で提供する必要がある(図4)

図4 HTTPリクエストは、基本的にはセッションレスである。HTTPには2つのリクエストが同じクライアントかどうかを確認する情報はない

 これを実現しているのがセッション管理である。セッション管理には、セッションIDといわれる自動生成されるストリングとセッション・オブジェクトといわれるクラス・オブジェクトが関連している。セッションIDによってWebブラウザとセッション・オブジェクトを紐付けし、セッション・オブジェクトに自由にデータを貼り付けることによってWebブラウザとユーザー・データを管理しようというものである。

 セッションIDは基本的にWebブラウザのクッキーに保存される。あるブラウザが初めてアプリケーション・サーバにアクセスしてきたとき、セッション管理機構がセッションIDを生成し、クッキーに保存する。次回以降のアクセスでは、このクッキーを読み出すことにより、そのWebブラウザが前にアクセスにきたことのあるものであることと、どのセッション・オブジェクトを利用しているかを認識する(図5)

図5 セッション管理の方法。基本的にセッションIDはWebブラウザのクッキーに保存される

 

コラム JSP、Servletを使ったセッション管理

 Webブラウザがクッキーをオフにしていると、セッション管理がうまくいかない。セッション管理機構がセッションIDをWebブラウザ上に保存できないからである。携帯電話などのブラウザ機能でも最新のものを除いてクッキーが使えない。

 このとき、セッション管理を行う方法として「URL再書き込み」という方法がある。これは、JSPやServletのAPIを使って、リンクのURLやFORMのactionに指定されるURLにセッションIDを埋め込む技術である。通常「MyServlet」というServletが呼び出される場合、URLは、

http://hostname/servlet/MyServlet

のようになるが、URL再書き込みでは、

http://hostname/servlet/MyServlet$sessionid=xxxxxxxxx

のようになる。これはURLなので、HTTPリクエストのURL部分に一緒に書き込まれるため、これによってもセッション管理がうまくいく。

 では、なぜこの方法が標準ではないのだろうか。それにはきちんとした理由がある。

 HTTPプロトコルをインターネット上で電子商取引に使うとき、暗号化が必要である。これには多くの場合SSLという暗号化技術が使われる。SSLはHTTPプロトコルの本文部分を暗号化する。HTTPリクエストの本文には、POST方式で作られたパラメータやクッキー情報が入る。GET方式でパラメータ渡しをする場合や、URL再書き込みによるセッションIDなどは、この暗号化に含まれない。このため、ネットワークトレースなどによるのぞき見行為に対して、URL再書き込みによるセッションIDは無防備であると言える。SSLを使ったサイトを構築するためには、GET方式やURL再書き込みは向いていないということである。

  1回1回のHTTPリクエストは、スレッド処理としてServletに送られる。基本的には、同じインスタンスで、複数のブラウザからのHTTPリクエストが、スレッドとなって同時に処理される可能性がある。これらがどうやって別々のセッションデータを管理するのだろうか。

 サーブレットの処理ルーチンとなるサービス・メソッド(servicedoGet、doPostなど)には、パラメータとしてHttpServletRequestHttpServletResponseオブジェクトが渡る。そのリクエストを送ってきたブラウザと紐付けされたセッション・オブジェクトは、HttpRequest.getSession()によってリクエスト・オブジェクトのインスタンスから取得することができる。セッション・オブジェクトには、名前を付けたオブジェクトを自由に貼り付けたり、取り出したりできるので、これによってWebブラウザごとのセッションにまたがったデータをメモリ上で簡単に管理することができる。これには、putValuegetValue メソッドを使う(図6)

図6 putValue、GetValueメソッドを使ってWebブラウザごとのセッションにまたがったデータをメモリ上で管理することができる


JSP(JavaServer Pages)

Keyword Index
[重点用語解説]
サーバサイドJavaテクノロジの重点キーワード
■Java Servlet
  ■JSP(JavaServer Pages)
  ■EJB(Enterprise Java Beans)
  


Java Agile フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Java Agile 記事ランキング

本日 月間