IThaiのブログ

IT関連の話題やタイに関する様々なことを書いていきます。

Tomcatのソースを読んでみる - Catalinaの読み込み

Web開発のアプリケーションサーバとして日頃とてもお世話になっているTomcat。

今まで使用させて頂いているだけで、その中身のソースについてはほぼ無勉強でした。

Javaで書かれているので、普段Javaを書いている私にも解読しやすいのでは?と思い、この機会にTomcatのソースリーディングしてみます。

まず、Tomcatの概要から調べてみます。

Tomcatの特徴

・開発元はApacheSoftwareFoundation。
・トップレベルプロジェクトのApacheTomcatProjectである。
・以前はApacheJakartaProjectだった。
・Javaプラットフォームで動作する。
・Webコンテナ(コンテナとはアプリケーション実行環境)と呼ばれる。
・ServletコンテナとしてServlet/JSPの動的コンテンツの仕組みを提供する。
・Servletコンテナがリクエスト毎にスレッド起動する。CGIより負荷が小さい。
・セッション管理ができる。

Tomcatの構成

・Catalina - Servlet コンテナ
・Coyote - HTTPサーバー
・Jasper, Jasper2 - JSP

Tomcatのディレクトリ構造

・bin - 実行ファイル類
・conf - 設定ファイル類
・lib
・temp
・logs - ログファイル類
・webapp - アプリケーションファイル
・work

Tomcatの主なクラス

・Bootstrapクラス
・Catalinaクラス
・Digesterクラス
・StandardEngineクラス
・StandardServerクラス
・StandardServiceクラス

では、実際にTomcatのソースを見て、Tomcatの処理を確認してみます。
まずは有名なBootstrapクラスから見てみます。
*分かりやすいようにメソッドの順番を変更しています。

public final class Bootstrap {

    /**
     * Daemon object used by main.
     */
    private static Bootstrap daemon = null;


    // -------------------------------------------------------------- Variables


    /**
     * Daemon reference.
     */
    private Object catalinaDaemon = null;


    protected ClassLoader commonLoader = null;
    protected ClassLoader catalinaLoader = null;
    protected ClassLoader sharedLoader = null;

    public static void main(String args[]) {

        if (daemon == null) {
            daemon = new Bootstrap();
            try {
                daemon.init();
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }

        try {
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

    /**
     * Initialize daemon.
     */
    public void init()
        throws Exception
    {

        // Set Catalina path
        setCatalinaHome();
        setCatalinaBase();

        initClassLoaders();

        Thread.currentThread().setContextClassLoader(catalinaLoader);

        SecurityClassLoad.securityClassLoad(catalinaLoader);

        // Load our startup class and call its process() method
        if (log.isDebugEnabled())
            log.debug("Loading startup class");
        Class startupClass =
            catalinaLoader.loadClass
            ("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.newInstance();

        // Set the shared extensions class loader
        if (log.isDebugEnabled())
            log.debug("Setting startup class properties");
        String methodName = "setParentClassLoader";
        Class paramTypes[] = new Class[1];
        paramTypes[0] = Class.forName("java.lang.ClassLoader");
        Object paramValues[] = new Object[1];
        paramValues[0] = sharedLoader;
        Method method =
            startupInstance.getClass().getMethod(methodName, paramTypes);
        method.invoke(startupInstance, paramValues);

        catalinaDaemon = startupInstance;

    }

    private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a 'single' env.
                commonLoader=this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

Bootstrap#mainで自身のインスタンスを作成し、
daemonにセットした後、daemon.init()で初期化処理を行います。
初期化処理では、initClassLoaders()でCatalinaPropertiesクラスを使って、
commonLoader、catalinaLoader、sharedLoaderを初期化しています。
そして、Catalinaクラスのインスタンスを生成し、 setParentClassLoaderを呼び出し、catalinaDaemonにセットしています。

    /**
     * Load daemon.
     */
    private void load(String[] arguments)
        throws Exception {

        // Call the load() method
        String methodName = "load";
        Object param[];
        Class paramTypes[];
        if (arguments==null || arguments.length==0) {
            paramTypes = null;
            param = null;
        } else {
            paramTypes = new Class[1];
            paramTypes[0] = arguments.getClass();
            param = new Object[1];
            param[0] = arguments;
        }
        Method method = 
            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        if (log.isDebugEnabled())
            log.debug("Calling startup class " + method);
        method.invoke(catalinaDaemon, param);

    }

daemon.load()でCatalina#loadを呼び出しています。

public class Catalina extends Embedded {

    protected String configFile = "conf/server.xml";

    /* 
     * Load using arguments
     */
    public void load(String args[]) {

        try {
            if (arguments(args))
                load();
        } catch (Exception e) {
            e.printStackTrace(System.out);
        }
    }

    /**
     * Start a new server instance.
     */
    public void load() {

        long t1 = System.nanoTime();

        initDirs();

        // Before digester - it may be needed

        initNaming();

        // Create and execute our Digester
        Digester digester = createStartDigester();

//--------------------------------------------------------中略

    }

Catalina#load()では、createStartDigester()にて、オブジェクトやルール
を設定してDigesterオブジェクトを作成しています。
そして、次からはconf/server.xmlを読み込んでいくのですが、
ちょっと長くなったので、次回に続きます。

WEBアプリケーション・サーバー 設計・構築ノウハウ 第2版

WEBアプリケーション・サーバー 設計・構築ノウハウ 第2版

  • 作者: NTTデータ先端技術株式会社 NTTデータ株式会社著,日経SYSTEMS
  • 出版社/メーカー: 日経BP社
  • 発売日: 2010/04/15
  • メディア: 単行本
  • 購入: 6人 クリック: 336回
  • この商品を含むブログ (6件) を見る