サーブレット・コンテキスト
|
|
サーブレット・コンテキストとは
サーブレット仕様書では、サーブレットを次のような概念でその構成を定義している。
つまりServletはServletConfig(構成)、init(初期化)、service(要求処理)、ServletInfo(サーブレット情報)の5つの要素から構成される。ServletConfはServletContext(コンテキスト:文脈とか周辺状況とかいう単語)とgetInitParameter(初期化パラメタ取得)、getServletContext(環境取得)からなる。それではServletContextとはいったい何であろうか。
この図からすると、InitParametersというクラスかインターフェイスが存在していても良さそうだが、これは存在しない。初期化パラメタは、ソフトウエアからは設定できず、このサーブレットを配備(デプロイメント)する人が設定する。具体的にはXMLで記されている導入記述書(DD: Deployment Descriptor)にinit-param要素として記述する。
ServletContextインターフェイスは、このサーブレットが走っているWebアプリケーションのサーブレット側からの観点を定義する。ServletContextインターフェイスはまたサーブレットがそれが使えるリソースへのアクセスを可能ならしめる。かかるオブジェクトを使って、サーブレットはイベントのログをとったり、リソースへのURLの参照を取得したり、またこのコンテキストの他のサーブレットが使えるよう属性(Attributes)の読み書きをしたりすることができる。
つまりServletContextというのは、各サーブレットにひとつ対応しているのでなく、Webアプリケーション毎にひとつ存在し、コンテナが保持・管理する。あるコンテキスト・パスにひとつServletContextのインスタンスが存在し、そのコンテキスト・パスで始まる全ての要求はこのインスタンスを通過する。サーブレット仕様書には次のように記されている。
「ServletContextはWebサーバの特定のパスのルートに置かれる。例えば、コンテキストはhttp://www.mycorp.com/catalogに置かれる。/catalog要求パス(コンテキスト・パス:context pathとして知られる)で始まるすべての要求はこのサーブレット・コンテキストに回される。ServletContextの唯一つのインスタンスがwebアプリケーション内のサーブレット(複数)に参照可能である。Webアプリケーションが配布可能としている場合は、Java仮想マシンあたり、アプリケーションあたりのServletContextオブジェクトの唯一つのインスタンスが使用中でなければならない。」
つまり、ServletContextはWebアプリケーションごとに存在し、このアプリケーションに属するサーブレット(JSPも)だけでなく、この仮想ホストに属する全てのサーブレットに共有される。つまりあるアプリケーション内のサーブレット間だけでなく、それが許可される場合はアプリケーション間のデータ交換に使うことができる。サーブレットは、オブジェクトを属性(Attribute)として名前を付けてこのコンテキストにバインドできる。バインドされたオブジェクトを、その仮想ホストに属する全てのサーブレットがアクセスできる。但し、分散環境では共有されないので、注意が必要である。なお、属性の名前を付ける規約は、パッケージ名のそれに順ずるようにとSunのチュートリアルに書かれている。
というわけで、ServletContextはウェブ・アプリケーションの配備の際にコンテナに設定される。指定はやはりDDで行う。
ここで、URIと各Pathとの関連を以下に示す。
要求URI = contextPath + servletPath + pathInfo
ContextPathというのは、ServletContextに対応したもので、呼ばれたサーブレットはこのコンテキストに属している。もしWebサーバの名前のベースにデフォルトとしてこのコンテキストが置かれているときは、この部分は空の文字列となる。それ以外の場合は’/’で始まるが、’/’では終わらない文字列となる。ServletPathというのは、このサーブレットへのマッピング・パタンに対応する部分で’/’で始まる。PathInfoは、上記Pathのどれにも含まれない部分である。
たとえばTomcatのconfというディレクトリにあるserver.xmlという設定ファイルには以下のような記述がある。
<Context path="/examples" docBase="webapps/examples" crossContext="false" debug="0" reloadable="true" > </Context> |
これが意味していることは、"/examples"というアプリケーションがあって、このアプリケーションのあるディレクトリは"webapps/examples"である。crossContext=trueにすると、ServletContext.getContext() メソッドを使って他のコンテキストにアクセスできる。ここではそれが許していない。debug="0"はデバッグのための出力情報レベルである。最後にreloadable="true"で再ロードを可能にしているので、変更が直ちに動作に反映される。
次に"webapps/examples"なるディレクトリの”WEB-INF”にあるweb.xmlを開いてみる。そこにはservlet-nameを基にしたクラス名とURLパタンのマッピングが定義されている。
<servlet> <servlet-name> servletToJsp </servlet-name> <servlet-class> servletToJsp </servlet-class> </servlet> |
<servlet-mapping> <servlet-name> servletToJsp </servlet-name> <url-pattern> /servletToJsp </url-pattern> </servlet-mapping> |
要求URIからContextPathを外した文字列に、指定したURLパタンに合致するものがあれば、それに対応したサーブレットに該要求が送られる。サーブレットがまだインスタンス化されていなければ、インスタンス化と初期化をした後に、そのインスタンスのserviceメソッドが呼び出される。
ところで皆さんはTomcatで実習した際、”/examples/servlet”と”/servlet”なるサーブレット・パスを指定したが、”/servlet”はどうなっているのかと思われるかもしれない。これは本来サーブレット呼び出しにはhttp://domain/servlet/myservletなどのように”/servlet”を付けていたなごりで、これをhttp://domain/myservletのように変換するインターセプタ(Invoker Interceptor)がserver.xml ファイルに記述されているからである。例えばTomcat3.2.1では、
<RequestInterceptor className="org.apache.tomcat.request.InvokerInterceptor" debug="0" prefix="/servlet/" /> |
と記されているであろう。ここに、プレフィックスはスラッシュで始まりスラッシュで終わる文字列にすることに注意されたい。なお、Tomcat 4.0 ではInvokerServletが使われている。
最後にTomcatのディレクトリ構造をまとめておこう。