Tomcat源碼分析--啟動過程

來源:互聯網
上載者:User

標籤:

      一直使用Tomcat確不知道它的運行原理。看了源碼後對它的啟動過程有了一定的瞭解,特來記錄一下。

      首先先介紹一下Tomcat的架構圖:

      Tomcat主要有兩個核心的組件,一個是Connector(連接器)和容器。所謂連接器就是當有HTTP請求到來時,連接器負責接收這個請求,然後將該請求轉寄到容器。容器有Engine,Host,Context,Wrapper。Engine:表示整個Catalina servlet引擎;Host:表示包含一個或多個Context容器的虛擬機器主機;Context:表示一個Web應用程式。一個Context可以有多個Wrapper;Wrapper:表示一個獨立的servlet。一個容器可以有0個或多個低層級的子容器。例如,一般情況下,一個Context執行個體會有一個或多個Wrapper執行個體。一個Host執行個體中會有0個或多個Context執行個體。但是,Wrapper類型處於層級結構的最底層,因此,它無法再包含子容器了。

      一般啟動Tomcat會是運行startup.bat或者startup.sh檔案,這兩個檔案最後都會調用,org.apache.catalina.startup包下面Bootstrap類的main方法。main方法具體實現如下:

main方法先執行個體化了一個Bootstrap執行個體,接著調用了init方法。init方法是生命週期方法,以後不再累述。接著看init的具體實現。

init方法,先初始化了類載入器。initClassLoaders方法具體實現如下:

createClassLoader具體實現細節不再顯示,有感興趣的讀者可以具體查看。該方法的具體簽名為:

private ClassLoader createClassLoader(String name, ClassLoader parent)  throws Exception

從方法簽名中可以看出createClassLoader需要傳入一個父載入器。從具體的代碼中可以看出,commonLoader類載入器是catalinaLoader類載入器和sharedLoader類載入器的父載入器。初始化完類載入器後,使用反射機制調用org.apache.catalina.startup.Catalina類下的setParentClassLoader方法。具體代碼是:

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);

因為Tomcat執行的是start操作,調用完init方法後,會執行load方法。

else if (command.equals("start")) {                daemon.setAwait(true);                daemon.load(args);                daemon.start();            }

load方法通過反射調用Catalina類的load方法。

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);    }

Catalina類的load方法:

public void load() {        long t1 = System.nanoTime();        initDirs();        // Before digester - it may be needed        initNaming();        // Create and execute our Digester        Digester digester = createStartDigester();        InputSource inputSource = null;        InputStream inputStream = null;        File file = null;        try {            try {                file = configFile();                inputStream = new FileInputStream(file);                inputSource = new InputSource(file.toURI().toURL().toString());            } catch (Exception e) {                if (log.isDebugEnabled()) {                    log.debug(sm.getString("catalina.configFail", file), e);                }            }            if (inputStream == null) {                try {                    inputStream = getClass().getClassLoader()                        .getResourceAsStream(getConfigFile());                    inputSource = new InputSource                        (getClass().getClassLoader()                         .getResource(getConfigFile()).toString());                } catch (Exception e) {                    if (log.isDebugEnabled()) {                        log.debug(sm.getString("catalina.configFail",                                getConfigFile()), e);                    }                }            }            // This should be included in catalina.jar            // Alternative: don‘t bother with xml, just create it manually.            if (inputStream == null) {                try {                    inputStream = getClass().getClassLoader()                            .getResourceAsStream("server-embed.xml");                    inputSource = new InputSource                    (getClass().getClassLoader()                            .getResource("server-embed.xml").toString());                } catch (Exception e) {                    if (log.isDebugEnabled()) {                        log.debug(sm.getString("catalina.configFail",                                "server-embed.xml"), e);                    }                }            }。。。。。。。。。。。。。。。。。。。        // Stream redirection        initStreams();        // Start the new server        try {            getServer().init();        } catch (LifecycleException e) {            if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {                throw new java.lang.Error(e);            } else {                log.error("Catalina.start", e);            }        }        long t2 = System.nanoTime();        if(log.isInfoEnabled()) {            log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");        }    }

load方法中比較重要的方法是createStartDigester(),createStartDigester方法主要的作用就是幫我們執行個體化了所有的服務元件包括server,service和connect。具體的執行個體化方法,

digester.addObjectCreate("Server",                                 "org.apache.catalina.core.StandardServer",                                 "className");        digester.addSetProperties("Server");        digester.addSetNext("Server",                            "setServer",                            "org.apache.catalina.Server");        digester.addObjectCreate("Server/GlobalNamingResources",                                 "org.apache.catalina.deploy.NamingResourcesImpl");        digester.addSetProperties("Server/GlobalNamingResources");        digester.addSetNext("Server/GlobalNamingResources",                            "setGlobalNamingResources",                            "org.apache.catalina.deploy.NamingResourcesImpl");        digester.addObjectCreate("Server/Listener",                                 null, // MUST be specified in the element                                 "className");        digester.addSetProperties("Server/Listener");        digester.addSetNext("Server/Listener",                            "addLifecycleListener",                            "org.apache.catalina.LifecycleListener");        digester.addObjectCreate("Server/Service",                                 "org.apache.catalina.core.StandardService",                                 "className");        digester.addSetProperties("Server/Service");        digester.addSetNext("Server/Service",                            "addService",                            "org.apache.catalina.Service");        digester.addObjectCreate("Server/Service/Listener",                                 null, // MUST be specified in the element                                 "className");        digester.addSetProperties("Server/Service/Listener");        digester.addSetNext("Server/Service/Listener",                            "addLifecycleListener",                            "org.apache.catalina.LifecycleListener");        //Executor        digester.addObjectCreate("Server/Service/Executor",                         "org.apache.catalina.core.StandardThreadExecutor",                         "className");        digester.addSetProperties("Server/Service/Executor");        digester.addSetNext("Server/Service/Executor",                            "addExecutor",                            "org.apache.catalina.Executor");        digester.addRule("Server/Service/Connector",                         new ConnectorCreateRule());        digester.addRule("Server/Service/Connector",                         new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName"}));        digester.addSetNext("Server/Service/Connector",                            "addConnector",                            "org.apache.catalina.connector.Connector");        digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",                                 "org.apache.tomcat.util.net.SSLHostConfig");        digester.addSetProperties("Server/Service/Connector/SSLHostConfig");        digester.addSetNext("Server/Service/Connector/SSLHostConfig",                "addSslHostConfig",                "org.apache.tomcat.util.net.SSLHostConfig");        digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",                         new CertificateCreateRule());        digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",                         new SetAllPropertiesRule(new String[]{"type"}));        digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",                            "addCertificate",                            "org.apache.tomcat.util.net.SSLHostConfigCertificate");        digester.addObjectCreate("Server/Service/Connector/Listener",                                 null, // MUST be specified in the element                                 "className");        digester.addSetProperties("Server/Service/Connector/Listener");        digester.addSetNext("Server/Service/Connector/Listener",                            "addLifecycleListener",                            "org.apache.catalina.LifecycleListener");        digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",                                  null, // MUST be specified in the element                                  "className");        digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");        digester.addSetNext("Server/Service/Connector/UpgradeProtocol",                            "addUpgradeProtocol",                            "org.apache.coyote.UpgradeProtocol");        // Add RuleSets for nested elements        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));        digester.addRuleSet(new EngineRuleSet("Server/Service/"));        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));        // When the ‘engine‘ is found, set the parentClassLoader.        digester.addRule("Server/Service/Engine",                         new SetParentClassLoaderRule(parentClassLoader));        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");

初始化操作完成後,接下來會執行catalina執行個體的start方法。

從上面載入的組件中,Tomcat會預設載入org.apache.catalina.core.StandardServer作為Server的執行個體類。

在Server的start的方法裡面會執行service的start方法。在createStartDigester()方法裡面,會預設載入org.apache.catalina.core.StandardService類。會接著調用Service的start方法。

service中會調用connector的start方法。至此Tomcat啟動完畢

Tomcat源碼分析--啟動過程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.