naobe @ ウィキ

Tomcat

最終更新:

Bot(ページ名リンク)

- view
管理者のみ編集可
OpenSourceに戻る

バージョンと標準

Tomcatバージョン servlet jsp
6.0 2.4 2.0
5.5 2.3 2.0

ソースプログラム


Tomcat6.0.3.5ソース解読

苦労しました。大筋は合っていると思う。
Tomcat解読.xls


起動

Bootstrap#startからCatalina#startを呼び出す。Server#startを実行し、Server.xmlで設定したポート番号でsocketのstreamからreadする。readした文字が"SHUTDOWN"なら停止処理を実行する。

server.xmlからデフォルトのポート番号は、8005になる。
 <Server port="8005" shutdown="SHUTDOWN">

 public class Catalina extends Embedded {
     public void start() {
 
         ((Lifecycle) getServer()).start();
 
         if (await) {
             await();
             stop();
         }
 
     public void await() {
         getServer().await();
     }
 
 
 
 public final class StandardServer
 
     public void await() {
             awaitSocket =
                 new ServerSocket(port, 1,
                                  InetAddress.getByName("localhost"));
 
             while (!stopAwait) {
                 ServerSocket serverSocket = awaitSocket;
                 Socket socket = null;
                 StringBuilder command = new StringBuilder();
                 try {
                     InputStream stream = null;
                         socket = serverSocket.accept();
                         socket.setSoTimeout(10 * 1000);  // Ten seconds
                         stream = socket.getInputStream();
 
                     // Read a set of characters from the socket
                     int expected = 1024; // Cut off to avoid DoS attack
                     while (expected < shutdown.length()) {
                         if (random == null)
                             random = new Random();
                         expected += (random.nextInt() % 1024);
                     }
                     while (expected > 0) {
                         int ch = -1;
                         try {
                             ch = stream.read();
                         } catch (IOException e) {
                             log.warn("StandardServer.await: read: ", e);
                             ch = -1;
                         }
                         if (ch < 32)  // Control character or EOF terminates loop
                             break;
                         command.append((char) ch);
                         expected--;
                     }
 
                 // Match against our command string
                 boolean match = command.toString().equals(shutdown);
                 if (match) {
                     break;
                 } 
             }
 

停止

Bootstrap#stopServerからCatalina#stopServerを呼び出す。
ソースは以下になっている。Serverのポート番号からソケットを作成して、"SHUTDOWN"という文字を送信している。

 public class Catalina extends Embedded {
 
     public void stopServer(String[] arguments) {
         ・・・・
         s = getServer();
         try {
             if (s.getPort()>0) { 
                 String hostAddress = InetAddress.getByName("localhost").getHostAddress();
                 Socket socket = new Socket(hostAddress, getServer().getPort());
                 OutputStream stream = socket.getOutputStream();
                 String shutdown = s.getShutdown();//  "SHUTDOWN"
                 for (int i = 0; i < shutdown.length(); i++)
                     stream.write(shutdown.charAt(i));
                 stream.flush();
                 stream.close();
                 socket.close();
             } else {
                 log.error(sm.getString("catalina.stopServer"));
                 System.exit(1);
             }
         } catch (IOException e) {
             log.error("Catalina.stop: ", e);
             System.exit(1);
         }


レルム

レルムとは、ユーザ、パスワード、ロールをまとめたもの。ユーザDBのエントリに相当する。UserDatabaseRealm、JDBCレルム、DataSourceレルム、JNDIレルムがある。web.xmlのセキュリティ設定で制限されたURLをアクセスするときに認証するためのユーザ、パスワード、ロールを定義したもの。web.xmlでは、URLとHTTPメソッドに対してロールを割り当てる。

UserDatabaseRealm

JNDIを介してアクセスするがデフォルトでは$CATALINA_BASE/conf/tomcat-user.xmlを使う。
$CATALINA_BASE/conf/server.xmlに以下を設定する。
 <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<Engine>直下に設定すると、Tomcat内の全ての仮想ホストで共通の設定になる
<Host>直下に設定すると、仮想ホスト内で共通の設定になる。
<Context>直下に設定すると、WEBアプリケーション内で共通の設定になる。

  • web.xmlで制限をかけたURLにアクセスすると、認証(BASIC,DIGEST,FORM)を行う。
  • 認証に成功すると、ユーザを内部に保管して、指定したURLに移動する。
  • BASIC認証の場合は、ブラウザを閉じる(TCPコネクションclose ?)までユーザをキャッシュする(認証を行わない)。
  • FORM認証の場合は、セッションタイムアウトになるまでユーザをキャッシュする。キャッシュされたユーザはセッションの直列化をまたがって保存されない(APサーバ停止によるセッションの保管のことでしょう)。

tomcat-users.xmlの設定例
 <tomcat-users>
   <user name="tomcat" password="tomcat" roles="tomcat" />
   <user name="role1"  password="tomcat" roles="role1"  />
   <user name="both"   password="tomcat" roles="tomcat,role1" />
 </tomcat-users>

データソース

Tomcat6.Xの内部データソースは、org.apache.tomcat.dbcp.dbcp.BasicDataSource。これは、org.apache.commons.dbcp.BasicDataSourceと同じもの。
http://www.flsi.co.jp/Java_text/vol140.htm 参照

設定

項目 内容
親を優先とするクラスローダの移譲 web.xmlのcontextのdelegate属性にtrueを設定する
セッションタイムアウト conf/web.xmlのsession-configタグを修正するとすべてのWEBアプリケーションに影響する。WEBアプリケーションのweb.xmlを修正すると、WEBアプリケーションのみ影響する。単位は分。

サーバ化


【環境】
tomcat バージョン:6.0
OS: CentOS 5.5

専用ユーザ作成

 #adduser -d tomcatインストールディレクトリ -s /sbin/nologin tomcat

所有者の変更

 #chown -R tomcat tomcatインストールディレクトリ
 #chmod -R g-r,g-w,g-x tomcatインストールディレクトリ

JAVA_HOME設定

$TOMCAT_INSTALL/binsetenv.shに以下を設定
 JAVA_HOME=JAVAホームディレクトリ
 JRE_HOME=JAVAホームディレクトリ

commons-daemon


commons-daemon概要

Javaは、signalに対応していないため、サーバの急なシャットダウンなどのタイミングでサーバリソース(TCP接続、DBとのコネクションなど)の正規の終結処理ができない。CとJavaを組み合わせてこれに対応したもの。UNIXとWindowsで異なるモジュールを提供する。UNIX版は、jsvc。

commons-daemonのインストール

http://commons.apache.org/daemon/download_daemon.cgi から以下をダウンロード
  • commons-daemon-1.0.5-src.tar.gz
  • commons-daemon-1.0.5.jar

  • commons-daemon-1.0.5-src.tar.gzを展開し以下を実行。

 [hoge@athlon4 tmp]$ cd commons-daemon-1.0.5-src
 [hoge@athlon4 commons-daemon-1.0.5-src]$ cd src/
 [hoge@athlon4 src]$ cd native/
 [hoge@athlon4 native]$ cd unix/
 [hoge@athlon4 unix]$ sh support/buildconf.sh
 [hoge@athlon4 unix]$ ./configure
 *** Current host ***
 checking build system type... i686-pc-linux-gnu
 checking host system type... i686-pc-linux-gnu
 checking cached host system type... ok
 *** C-Language compilation tools ***
 checking for gcc... gcc
 checking for C compiler default output file name... a.out
 checking whether the C compiler works... yes
 checking whether we are cross compiling... no
 checking for suffix of executables...
 checking for suffix of object files... o
 checking whether we are using the GNU C compiler... yes
 checking whether gcc accepts -g... yes
 checking for gcc option to accept ANSI C... none needed
 checking for ranlib... ranlib
 checking for strip... strip
 *** Host support ***
 checking C flags dependant on host system type... ok
 *** Java compilation tools ***
 checking for sablevm... NONE
 checking for kaffe... NONE
 checking for javac... /usr/java/jdk1.6.0_21/bin/javac
 /usr/java/jdk1.6.0_21/bin/javac
 checking wether the Java compiler (/usr/java/jdk1.6.0_21/bin/javac) works... yes
 checking for jar... /usr/java/jdk1.6.0_21/bin/jar
 gcc flags added
 checking for cap_init in -lcap... yes
 *** Writing output files ***
 configure: creating ./config.status
 config.status: creating [[Makefile]]
 config.status: creating Makedefs
 config.status: creating native/Makefile
 *** All done ***
 Now you can issue "make"
 [hoge@athlon4 unix]$ make clean
 (cd native; make  clean)
 make[1]: ディレクトリ `/home/hoge/tmp/commons-daemon-1.0.5-src/src/native/unix/native' に入ります
 rm -f arguments.o debug.o dso-dlfcn.o dso-dyld.o help.o home.o java.o location.o replace.o locks.o signals.o ../jsvc jsvc-unix.o libservice.a
 make[1]: ディレクトリ `/home/hoge/tmp/commons-daemon-1.0.5-src/src/native/unix/native' から出ます
 [hoge@athlon4 unix]$ make
 (cd native; make  all)
 make[1]: ディレクトリ `/home/hoge/tmp/commons-daemon-1.0.5-src/src/native/unix/native' に入ります
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c jsvc-unix.c -o jsvc-unix.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c arguments.c -o arguments.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c debug.c -o debug.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c dso-dlfcn.c -o dso-dlfcn.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c dso-dyld.c -o dso-dyld.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c help.c -o help.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c home.c -o home.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c java.c -o java.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c location.c -o location.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c replace.c -o replace.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c locks.c -o locks.o
 gcc -g -O2 -DOS_LINUX -DDSO_DLFCN -DCPU=\"i386\" -Wall -Wstrict-prototypes -DHAVE_LIBCAP  -I/usr/java/jdk1.6.0_21/include -I/usr/java/jdk1.6.0_21/include/linux -c signals.c -o signals.o
 ar cr libservice.a arguments.o debug.o dso-dlfcn.o dso-dyld.o help.o home.o java.o location.o replace.o locks.o signals.o
 ranlib libservice.a
 gcc   jsvc-unix.o libservice.a -ldl -lpthread -lcap -o ../jsvc
 make[1]: ディレクトリ `/home/hoge/tmp/commons-daemon-1.0.5-src/src/native/unix/native' から出ます
 [hoge@athlon4 unix]$

  • 作成されたjsvcのownerをtomcatに修正して${TOMCAT_HOME}/binにコピー
  • /etc/init.dに起動スクリプト作成
 #
 # source function
 #
 . /etc/init.d/functions
 #
 # That is for Tomcat-5.0.x (Apache Tomcat/5.0)
 #
 # Adapt the following lines to your configuration
 JAVA_HOME=/usr/java/jdk1.6.0_21
 CATALINA_HOME=/opt/apache-tomcat-6.0.29
 TOMCAT_USER=tomcat
 
 # for multi instances adapt those lines.
 TMP_DIR=/tmp
 PID_FILE=/var/run/jsvc.pid
 LOCKFILE=/var/lock/subsys/tomcat
 CATALINA_BASE=$CATALINA_HOME
 
 CATALINA_OPTS=
 CLASSPATH=\
 $JAVA_HOME/lib/tools.jar:\
 #$CATALINA_HOME/bin/commons-daemon.jar:\
 $CATALINA_HOME/bin/commons-daemon-1.0.5.jar:\
 $CATALINA_HOME/bin/bootstrap.jar
 
 case "$1" in
   start)
     echo -n "Starting jsvc: "
     #
     # Start Tomcat
     #
     $CATALINA_HOME/bin/jsvc \
     -user $TOMCAT_USER \
     -home $JAVA_HOME \
     -Dcatalina.home=$CATALINA_HOME \
     -Dcatalina.base=$CATALINA_BASE \
     -Djava.io.tmpdir=$TMP_DIR \
     -wait 10 \
     -pidfile $PID_FILE \
     -outfile $CATALINA_HOME/logs/catalina.out \
     -errfile '&1' \
     $CATALINA_OPTS \
     -cp $CLASSPATH \
     org.apache.catalina.startup.Bootstrap
     #
     # To get a verbose JVM
     #-verbose \
     # To get a debug of jsvc.
     #-debug \
     RETVAL=$?
     if [ $RETVAL = 0 ]; then
         echo_success
         touch $LOCKFILE
     else
         echo_failure
     fi
     echo
     ;;
 
   stop)
     #
     # Stop Tomcat
     #
     $CATALINA_HOME/bin/jsvc \
     -stop \
     -pidfile $PID_FILE \
     org.apache.catalina.startup.Bootstrap
     RETVAL=$?
     if [ $RETVAL = 0 ]; then
         echo_success
         rm -f $PIDFILE $LOCKFILE
     else
         echo_failure
     fi
     echo
     ;;
 
   *)
     echo "Usage tomcat start/stop"
     exit 1;;
 esac

プロセス

上記の設定でjsvcを起動すると、オーナがrootのプロセスとtomcatのプロセスが常駐する。指定のポート番号をlistenしているのは、tomcatのプロセス。

Tomcatのクラスローダ

以下、Tomcat6の場合。


クラスローダ 対象ロケーション 説明
WEBアプリケーション WEB-INF/classes,WEB-INF/lib 他のWEBアプリケーションからは使われないクラスローダ
Shared <tomcat>/shared/lib, <tomcat>/shared/lib/*.jar。<tomcat>/conf/catalina.propertiesのshared.loaderに設定する。設定がなければcommonローダと同じ。 WEBアプリケーションが共用するクラスローダ
Catalina <tomcat>/conf/catalina.propertiesのserver.loaderに設定。設定がなければcommonローダと同じ。 Tomatの実行に使用される。WEBアプリケーションから使えないクラスローダ
common <tomcat>/lib,<tomcat>/lib/*.jar <tomcat>/conf/catalina.propertiesのcommon.loaderに設定されている。 TomcatとWEBアプリケーションの両方から使われるクラスローダ

委譲の優先順位
  1. ブートストラップ・クラスローダ
  2. システム・クラスローダ
  3. Webアプリケーション自身のクラスローダ
  4. Commonクラスローダ
  5. Sharedクラスローダ

WEBアプリケーション

<Tomcat>/webapps下にディレクトリを作成すると、そのディレクトリ名のWEBアプリケーション(コンテキストパスがディレクトリ名)が追加される。

任意のディレクトリをWEBアプリケーションに追加するには、conf/server.xmlに以下を設定。

 <Server >
   <Service>
     <Engine>
       <Host>
         <Context path="/naobe"
            docBase="c:/webapps/naobe"
            debug="0"
            reloadable="true"
            >
         </Context>

c:/webapps/naobe以下のディレクトリ構成は以下。

 WEB-INF
   +-- web.xml
   +-- classes
          |
          +-- パッケージ、クラスファイル
   +-- lib

docBaseは、Tomcatインストールディレクトリからの相対ディレクトリも指定可能。
http://localhost:8080/naobeでWEBアプリケーションを参照できる。
人気記事ランキング
ウィキ募集バナー