Java - Servlet(W2K + Tomcat) について自分メモ(2002/08/12) 
 

■Servlet の仕組みめも

よくどのサイトでも記述されている通りに Tomcat を インストールした場合、Servlet のサンプルを動作させて見ましょう!という記述で終わってしまい、Servlet と Tomcat の仕組みがよくわからないままに終わってしまいます。(実際書籍でも、そのレベルが多い)

そこで、自分メモとしては Serlvet と Tomcat の仕組みに重点をおいてと言うかそこらへんを掘り下げてカキカキしてみます。

 

Tomcat 付属の Serlvet の "Hello World!!" サンプルを実行させるためには、"http://localhost:8080/examples/servlet/HelloWorldExample"ってブラウザ上から指定しますが、実はこの指定には、重要なポイントがいくつも存在するのです。

その1:Tomcat を インストール(なにも考えず)すると、"C:\Program Files\Apache Group\Tomcat 4.1"(以下 $CATALINA_HOME) に展開されます。その下の "\webapps" が、"Hello World!!" の Servlet が存在するのですが、下記ディレクトリ階層図をみてもわかる通り変わったディレクトリ構造になってます。

その2:上記をみて判る通り "\webapps" ディレクトリ階層にはいくつものディレクトリがあります。その中で重要なのが "\WEB-INF" と "\WEB-INF\classes" です。この2つのディレクトリは、必ず必要です。どーして必要なのかと言うと(←この説明が本では、ろくにされていない)

・"\WEB-INF"  Servlet を構成すべきディレクトリのお約束トップディレクトリ

・"\WEB-INF\classes"  この下に Servlet をおきます

その3:で実際 "Hello World!!" の Servlet は、"$CATALINA_HOME\webapps\examples\WEB-INF\classes\HelloWorldExample.java" ってあります。これが実行されているのです。

ここまで説明してて勘のよい人ならわかる通り何故 "http://localhost:8080/examples/servlet/HelloWorldExample" が、実行されるのかと? "/examples" って自動?って? そんな事はありません。

その1:"/examples" の 指定は、"$CATALINA_HOME\conf\server.xml" の下記部分に記述されてました。

<Context path="/examples" docBase="examples" debug="0"
reloadable="true" crossContext="true">

・path には、URL上で指定される "http://localhost:8080" 以降のパス名を指定

・docBase には、上記パス名が指定された場合に実際のディレクトリと関連する場所を指定

その2:上記 docBase の指定は、パスを指定しないと $CATALINA_HOME 以下のディレクトリを指します。ですので任意のディレクトリを指したい場合には、下記の様にしてもいいでしょう。

<Context path="/samples2" docBase="C:/murachi/dep" debug="0"
reloadable="true" crossContext="true" />

また、まだ1つありますここまで説明しててまだ勘のよい人ならわかる通り何故 "http://localhost:8080/examples/servlet/HelloWorldExample" え? "/servlet" ってどこよ!って。

その1:"/servlet" は、"\WEB-INF\classes" とおきかえられるのです。(←わかりずらい!)

ってずらずら書きましたが、ここのサイトがわかりやすい。

■Servlet の仕組みめも2

上記デフォルトのままですと Java で Servlet なのかい!ってバレバレですので、ちょっとだけテクニックを使って見ましょう。"$CATALINA_HOME\webapps\examples\WEB-INF\web.xml" に下記の記述を追加します。

<!-- murachi test その1 -->
<servlet> 
    <servlet-name>HelloWorldMura</servlet-name>
    <servlet-class>HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping> 
    <servlet-name>HelloWorldMura</servlet-name>
    <url-pattern>/hoge/HelloWorldMura</url-pattern>
</servlet-mapping> 

<!-- murachi test その2 -->
<servlet> 
    <servlet-name>HelloWorldMura2</servlet-name>
    <servlet-class>HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping> 
    <servlet-name>HelloWorldMura2</servlet-name>
    <url-pattern>/HelloWorldMura</url-pattern>
</servlet-mapping> 

Tomcat を再起動して、下記のURLを実行してみてください。結果は全て同じですが意図するところを理解してくれましたか?

http://localhost:8080/examples/servlet/HelloWorldExample

http://localhost:8080/examples/hoge/HelloWorldMura  (←その1)

http://localhost:8080/examples/HelloWorldMura  (←その2)

■Tomcat が停止しない?

Tomcat インストール時に "NT Service"としてチェックした場合、Tomcat のサービスを停止することができません(はまった!)。これは、OSのサービスとして登録してしまいマシン起動時に自動的に実行される状態となってしまい通常のプロセス停止ができなくなってしまうからです。

やってみると判りますが、「Windows タスク マネージャ」の「プロセス」タブのなかに、 "tomcat.exe" という名前でエントリーが存在しそれを終了しても停止しませんし、スタートメニューの "Stop Tomcat" ショートカットアイコンからも停止することができません。

実際、上記の設定は Windows で Tomcat をサービス運用する場合には有効な手法ですが、Servlet開発時には Tomcat の再起動を頻繁に行うため実現的ではありません。ですので開発時には、Tomcat をインストールするとき "NT Service"を選択しない方がよいでしょう。間違ってインストールしてしまった場合は、下記の手順にてその状態を解除することができます(Tomcat の再インストールをするっていう手段もあります)。

「コントロール パネル」の「管理ツール」から、「サービス」アイコンをダブルクリック。 
サービスのエントリの中から、 "Apache Tomcat" を右クリックして、開いたコンテキスト・メニューの「停止」を選ぶ。このとき、「Windows タスク マネージャ」の「プロセス」タブのリストの中から "tomcat.exe" が消えていることが確認できる。 
続いて、「サービス」の "Apache Tomcat" を右クリックして、開いたコンテキスト・メニューの「プロパティ(R)」を選ぶと、「(ローカル コンピュータ上) Apache Tomcat のプロパティ」のシートが開く。 
このシートの「全般」タブの「スタートアップの種類(E)」が「自動」になっているので、「手動」に変更する。 
これで、OS立ち上げ時に Tomcat がサービスとして起動することがなくなります

■ WEB-INF\web.xml で記述できる代表的なタグ

・<init-param>

  Servlet 起動時のパラメタを指定することができます。

  getInitParameter メソッドによりパラメタを取得します。

・<load-on-startup>

  init 関数をオーバーライドすることにより独自処理を実行できます。

・<servlet-mapping>

  url に対してのマッピングと class の実行を指定できます。

■Tomcat のウインドウにエラー?

\WEB-INF\web.xml を追加していくと次第に、Tomcatを起動するウインドウにエラーが表示されるようになりました。

2003/08/12 17:33:37 org.apache.commons.digester.Digester error
致命的: Parse Error at line 62 column 11: The content of element type "web-app" must match "(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)".
org.xml.sax.SAXParseException: The content of element type "web-app" must match"(icon?,display-name?,description?,distributable?,context-param*,filter*,filter-mapping*,listener*,servlet*,servlet-mapping*,session-config?,mime-mapping*,welcome-file-list?,error-page*,taglib*,resource-env-ref*,resource-ref*,security-constraint*,login-config?,security-role*,env-entry*,ejb-ref*,ejb-local-ref*)".
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.error(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
at org.apache.xerces.impl.dtd.XMLDTDValidator.endElement(Unknown Source)

at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) 

なんだろう?って調べてみるとどうやら web.xml の記述ルールが間違っているということがわかりました。例えば下記の記述ですとエラーになるので

<!-- murachi test その1 -->
<servlet> 
    <servlet-name>HelloWorldMura</servlet-name>
    <servlet-class>HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping> 
    <servlet-name>HelloWorldMura</servlet-name>
    <url-pattern>/hoge/HelloWorldMura</url-pattern>
</servlet-mapping> 

<!-- murachi test その2 -->
<servlet> 
    <servlet-name>HelloWorldMura2</servlet-name>
    <servlet-class>HelloWorldExample</servlet-class>
</servlet>
<servlet-mapping> 
    <servlet-name>HelloWorldMura2</servlet-name>
    <url-pattern>/HelloWorldMura</url-pattern>
</servlet-mapping> 

下のように修正するとエラーも表示されなくなりました。個人的には、定義部分ってその Servlet 単位のブロックというかまとまった指定の方が見易いんだけど・・・・と思うんですけど。仕様ならば仕方ないかなーっと。で、で、定義部もきちんと順序があるので間違っていると容赦なく怒られます(エラー)。

<servlet> 
    <servlet-name>HelloWorldMura</servlet-name>
    <servlet-class>HelloWorldExample</servlet-class>
</servlet>

<servlet> 
    <servlet-name>HelloWorldMura2</servlet-name>
    <servlet-class>HelloWorldExample</servlet-class>
</servlet>

<servlet-mapping> 
    <servlet-name>HelloWorldMura</servlet-name>
    <url-pattern>/hoge/HelloWorldMura</url-pattern>
</servlet-mapping> 

<servlet-mapping> 
    <servlet-name>HelloWorldMura2</servlet-name>
    <url-pattern>/HelloWorldMura</url-pattern>
</servlet-mapping>