深入理解Tomcat(七)Server和Service

前言

回顧【深入理解Tomcat(三)架構(gòu)及組件】,同時(shí)參考tomcat自帶的server.xml,我們發(fā)現(xiàn)在連接器(Connector)和容器(Container)外層主要是ServerService?;谟赏舛鴥?nèi)、由淺入深的方式,本文先來(lái)分析ServerService。

這兒,我們?cè)?a href="http://www.itdecent.cn/p/2b6359daf5c8" target="_blank">【深入理解Tomcat(三)架構(gòu)及組件】之上增加一張更為完整的整體結(jié)構(gòu)圖!

整體結(jié)構(gòu)圖

【深入理解Tomcat(二)Lifecycle】中,我們分析了Lifecycle,也知道了每個(gè)tomcat組件都有init()、start()等生命周期方法。因?yàn)長(zhǎng)ifecycle是基于模板方法模式設(shè)計(jì)的,init()會(huì)調(diào)用initInternal(),而start()會(huì)調(diào)用startInternal()。為了降低分析源碼的復(fù)雜性,我們?cè)趯?duì)每個(gè)組件進(jìn)行分析的時(shí)候,只會(huì)關(guān)心生命周期接口下的模板方法,而不會(huì)重復(fù)分析其下的非模板方法!

Server

  1. Catalina.load()里面調(diào)用了Server.init()方法。
  2. Catalina.start()里面調(diào)用了Server.start()方法。

所以我們從Serverinit()start()著手分析。

在分析之前,我們先看看Server有哪些方法:

/**
 * A <code>Server</code> element represents the entire Catalina
 * servlet container.  Its attributes represent the characteristics of
 * the servlet container as a whole.  A <code>Server</code> may contain
 * one or more <code>Services</code>, and the top level set of naming
 * resources.
 * <p>
 * Normally, an implementation of this interface will also implement
 * <code>Lifecycle</code>, such that when the <code>start()</code> and
 * <code>stop()</code> methods are called, all of the defined
 * <code>Services</code> are also started or stopped.
 * <p>
 * In between, the implementation must open a server socket on the port number
 * specified by the <code>port</code> property.  When a connection is accepted,
 * the first line is read and compared with the specified shutdown command.
 * If the command matches, shutdown of the server is initiated.
 * <p>
 * <strong>NOTE</strong> - The concrete implementation of this class should
 * register the (singleton) instance with the <code>ServerFactory</code>
 * class in its constructor(s).
 *
 * @author Craig R. McClanahan
 */
public interface Server extends Lifecycle {

    // ------------------------------------------------------------- Properties

    public NamingResourcesImpl getGlobalNamingResources();
    public void setGlobalNamingResources
        (NamingResourcesImpl globalNamingResources);
    public javax.naming.Context getGlobalNamingContext();
    public int getPort();
    public void setPort(int port);
    public String getAddress();
    public void setAddress(String address);
    public String getShutdown();
    public void setShutdown(String shutdown);
    public ClassLoader getParentClassLoader();
    public void setParentClassLoader(ClassLoader parent);
    public Catalina getCatalina();
    public void setCatalina(Catalina catalina);
    public File getCatalinaBase();
    public void setCatalinaBase(File catalinaBase);
    public File getCatalinaHome();
    public void setCatalinaHome(File catalinaHome);


    // --------------------------------------------------------- Public Methods

    public void addService(Service service);
    public void await();
    public Service findService(String name);
    public Service[] findServices();
    public void removeService(Service service);
    public Object getNamingToken();
}

除了Server本身包含的方法addService(Service service)Service[] findServices(),我們額外閱讀并翻譯一下Server的javadoc注釋。

  1. 一個(gè)Server節(jié)點(diǎn)代表整個(gè)Catalina servlet容器。它的屬性代表這個(gè)servlet容器的所有特征。一個(gè)Server可以包含1個(gè)或多個(gè)Service,以及頂級(jí)名字資源。
  2. 正常情況下,該接口的實(shí)現(xiàn)類也必須實(shí)現(xiàn)Lifecycle接口,因此當(dāng)start()stop()方法被調(diào)用的時(shí)候,所有定義在其下面每個(gè)Servicestart()stop()也必須相應(yīng)地得到調(diào)用。
  3. 實(shí)現(xiàn)類必須在指定的端口號(hào)打開一個(gè)server socket(服務(wù)器套接字)。當(dāng)一個(gè)連接被接受,且第一行讀取之后,需要比較特殊的shutdown命令,如果命令匹配成功,則Server的shutdown操作將被發(fā)起。

Server的實(shí)現(xiàn)類為StandardServer,我們分析一下StandardServer.initInternal()方法。該方法用于對(duì)Server進(jìn)行初始化,關(guān)鍵的地方就是代碼最后對(duì)services的循環(huán)操作,對(duì)每個(gè)service調(diào)用init方法。
【注】:這兒我們只粘貼出這部分代碼。

@Override
protected void initInternal() throws LifecycleException {
    super.initInternal();

    // Initialize our defined Services
    for (int i = 0; i < services.length; i++) {
        services[i].init();
    }
}

初始化完成之后接著會(huì)調(diào)用start()方法,還是很簡(jiǎn)單,其實(shí)就是調(diào)用每個(gè)service的start()方法。

@Override
protected void startInternal() throws LifecycleException {

    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    setState(LifecycleState.STARTING);

    globalNamingResources.start();

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

Service

既然一個(gè)Server可以包含多個(gè)Service,對(duì)一個(gè)Serverinit()start()操作,其實(shí)就是對(duì)Server下的每個(gè)Service進(jìn)行init()start()操作。所以,我們接下來(lái)要分析的必然是Service。因?yàn)?code>Service的實(shí)現(xiàn)類為StandardService,所以我們就分析這個(gè)實(shí)現(xiàn)類。

我們先來(lái)看看init()方法。

@Override
protected void initInternal() throws LifecycleException {
    super.initInternal();

    if (engine != null) {
        engine.init();
    }

    // Initialize any Executors
    for (Executor executor : findExecutors()) {
        if (executor instanceof JmxEnabled) {
            ((JmxEnabled) executor).setDomain(getDomain());
        }
        executor.init();
    }

    // Initialize mapper listener
    mapperListener.init();

    // Initialize our defined Connectors
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            try {
                connector.init();
            } catch (Exception e) {
                String message = sm.getString(
                        "standardService.connector.initFailed", connector);
                log.error(message, e);

                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                    throw new LifecycleException(message);
            }
        }
    }
}

Serviceinit()操作主要做了幾件事情:

  1. Engine的初始化操作
  2. Service線程執(zhí)行器(tomcat中對(duì)java.util.concurrent.Executor的實(shí)現(xiàn))的初始化操作
  3. MapperListener的初始化操作
  4. 對(duì)Connectors(可能有多個(gè))的初始化操作

【注】:Engine、MapperListener、Mapper和Connector我們會(huì)在后面章節(jié)詳細(xì)分析,本節(jié)不做深入討論。我們這兒只需要知道Mapper的作用,主要是通過(guò)請(qǐng)求url快速和精確地找到相應(yīng)的Wrapper。

接下來(lái)我們看看Servicestart()方法

@Override
protected void startInternal() throws LifecycleException {
    if(log.isInfoEnabled())
        log.info(sm.getString("standardService.start.name", this.name));
    setState(LifecycleState.STARTING);

    // Start our defined Container first
    if (engine != null) {
        synchronized (engine) {
            engine.start();
        }
    }

    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }

    mapperListener.start();

    // Start our defined Connectors second
    synchronized (connectorsLock) {
        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);
            }
        }
    }
}

Serviceinit()類似,分別調(diào)用了Engine、Executors、MapperListener和Connectors的start()方法。

總結(jié)

本節(jié),我們重新詳細(xì)全面地拆分了Tomcat組件的整體架構(gòu)圖,知道了組件的包含關(guān)系和數(shù)量映射關(guān)系。其關(guān)系如下:

  1. 1個(gè)Catalina包含1個(gè)Server
  2. 1個(gè)Server包含多個(gè)Service
  3. 每個(gè)Service對(duì)應(yīng)有下面的組件
    1. 1個(gè)Engine
    2. 多個(gè)Connector
    3. 一個(gè)MapperListener
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容