tomcatソース学習2----起動プロセス


今回はtomcatの起動プロセスを分析します.
一、main関数分析
tomcatのエントリ関数は:org.apache.catalina.startup.mainのこの関数で最も重要なコードセグメントは次のとおりです.
    public static void main(String args[]) {
        //......
            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 if (command.equals("configtest")) {
                daemon.load(args);
                if (null==daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        //......

    }

ここから、起動パラメータが「start」の場合、実際に呼び出されるのはBootstrapであることがわかる.start()関数(daemonはBootstrapクラスのインスタンスです)、次にstart()関数を解析します.
二、start関数分析
Bootstrap.start()関数のコード:
    public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
        method.invoke(catalinaDaemon, (Object [])null);

    }

本質的にcatalinaDaemonのstart関数が呼び出されていることがわかりますが、catalinaDaemonはどのクラスのインスタンスですか?次のコードを使用して、次のことを確認します.
    public void init()throws Exception
    {

        // ......
        Class<?> startupClass =
            catalinaLoader.loadClass
            ("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.newInstance();
        //......
        catalinaDaemon = startupInstance;

    }

コードはorgに進みますapache.catalina.startup.Catalina.start()で行き、
public void start() {

        if (getServer() == null) {
            load();
        }
        //......
        getServer().start();
        //......
        if (await) {
            await();
            stop();
        }
    }

ここで最も重要な2つの関数は、1、load()、プロファイルのロード2、getServe日()です.start()は、サービスの開始です.もう1つ注意しなければならないのはawait()関数です.この関数は実際にはshutdownコマンドを監視しています.デフォルトは8005ポートで、プロファイルで設定できます.
三、配置ファイルのロード
tomcatのプロファイルのロードはorg.apache.catalina.startup.Catalina.load()関数で完了したコードは次のとおりです.
    public void load() {
        //......
        Digester digester = createStartDigester();
        //......
        inputSource.setByteStream(inputStream);
        digester.push(this);
        digester.parse(inputSource);
        //......
        getServer().init();
        //......
    }

この関数では主に3つのことをしました:1、xml解析実行構成を構築しました2、構成ファイルを解析し、最初のステップで生成した構築方式に基づいてtomcatのすべてのインスタンスを構築しました.3、サービスインスタンスが第2ステップで構築されたサービスを初期化する.初期化された論理プロシージャは、起動プロシージャの論理と非常に類似しており、特定の論理は起動プロシージャを参照することができる.具体的なロードプロセスは、次のブログで分析されます.
四、サービスの起動過程
start関数でgetServer()が呼び出されます.start()関数はtomcatサービスを起動することです.解析によりgetServer関数がorgを返すことがわかる.apache.catalina.core.StandardServerクラスのインスタンス.start関数はそのベースクラスorgである.apache.catalina.util.LifecycleBaseで実装されているキーコードは次のとおりです.
@Override
public final synchronized void start() throws LifecycleException {
    //...... 
    startInternal();
    //...... 
}

この関数の本質はstartInternal関数を呼び出し、StandardServerクラスでこの関数を実現することであり、そのキーコードは以下の通りである.
    @Override
    protected void startInternal() throws LifecycleException {

        // ......
        synchronized (services) {
            for (int i = 0; i < services.length; i++) {
                services[i].start();
            }
        }
    }

serverの起動中に実際に呼び出されたのは、各servicesのstart関数であることがわかります.ここでのservicesのデフォルトはStandardServiceのインスタンスであり、StandardServiceもLifecycleBaseを継承しているので、本質的にはStandardServiceのstartInternal関数が呼び出されます.この関数のキーコードは、
    @Override
    protected void startInternal() throws LifecycleException {


        //......
        if (container != null) {
            synchronized (container) {
                container.start();
            }
        }
        //......
        synchronized (executors) {
            for (Executor executor: executors) {
                executor.start();
            }
        }
        //......
        synchronized (connectors) {
            for (Connector connector: connectors) {
                try {
                    // If it has already failed, don't try and start it
                    if (connector.getState() != LifecycleState.FAILED) {
                        connector.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }

この関数では主に3つのことをしました:1、containerを呼び出すstart関数、containerのデフォルトはorg.apache.catalina.core.StandardEngineのインスタンスで、LifecycleBaseも継承されています.2、すべてのExecutorのstart関数を呼び出し、ExecutorもLifecycleBaseを継承します.3、すべてのconnectorのstart関数を呼び出し、connectorはorg.apache.catalina.connector.Connectorのインスタンスで、LifecycleBaseも継承されています.
containerのstartコードは本質的に実行されるContainerBaseである.startInternal関数、キーコード:
@Override
    protected synchronized void startInternal() throws LifecycleException {

        // ......
        if ((loader != null) && (loader instanceof Lifecycle))
            ((Lifecycle) loader).start();
        logger = null;
        getLogger();
        if ((manager != null) && (manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        Realm realm = getRealmInternal();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();
        if ((resources != null) && (resources instanceof Lifecycle))
            ((Lifecycle) resources).start();

        // Start our child containers, if any
        Container children[] = findChildren();
        List<Future<Void>> results = new ArrayList<Future<Void>>();
        for (int i = 0; i < children.length; i++) {
            results.add(startStopExecutor.submit(new StartChild(children[i])));
        }

        boolean fail = false;
        for (Future<Void> result : results) {
            try {
                result.get();
            } catch (Exception e) {
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
                fail = true;
            }

        }
        //......
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();


        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();

    }

ここでもLifecycleBaseインスタンスのstart関数を呼び出して起動します.
コネクタのstart呼び出しのキーコード:
    @Override
    protected void startInternal() throws LifecycleException {
        //......
        protocolHandler.start();
        //......
    }

ここで最も重要なのはhttpのhandlerのstartを呼び出し、イーサネットサーバを起動し、データの受信を待つことであり、具体的な起動と実行原理は後で分析される.
これでtomcatの起動過程はすでに初歩的に分析して遊んだ.