天天看點

Tomcat 體系結構、關鍵元件及生命周期管理

圖示Tomcat 的頂層結構

Tomcat 體系結構、關鍵元件及生命周期管理
Tomcat 體系結構、關鍵元件及生命周期管理

Service 連接配接 container(1)和 connector(N)

A Service is an intermediate component which lives inside a Server and ties one or more Connectors to exactly one Engine.

Service接口的标準實作類 StandardService(implements Lifecycle、service、和MbeanRegistration 接口的所有方法)

注意:同一個service的所有站點共享connector,是以監聽端口都一樣,除非配置不同的 Service實作區分的端口監聽。

主要方法 StandardService.SetContainer

public void setContainer(Container container) {
    Container oldContainer = this.container;
    //如果已經啟動了 container(目前service已經關聯container),則結束它的生命周期
    if ((oldContainer != null) && (oldContainer instanceof Engine))
        ((Engine) oldContainer).setService(null);
    //替換新的關聯
    this.container = container;
    if ((this.container != null) && (this.container instanceof Engine))
        ((Engine) this.container).setService(this);
    if (started && (this.container != null) && (this.container instanceof Lifecycle)) {
        try {
            ((Lifecycle) this.container).start();
        } catch (LifecycleException e) {
            ;
        }
    }
    //修改container時,需關聯到每個connector
    synchronized (connectors) {
        for (int i = ; i < connectors.length; i++)
            connectors[i].setContainer(this.container);
    }
    //停止舊的container
    if (started && (oldContainer != null) && (oldContainer instanceof Lifecycle)) {
        try {
            ((Lifecycle) oldContainer).stop();
        } catch (LifecycleException e) {
            ;
        }
    }
    support.firePropertyChange("container", oldContainer, this.container);
}
           

主要方法:StandardService.addConnector

public void addConnector(Connector connector) {
    synchronized (connectors) {
        connector.setContainer(this.container);
        connector.setService(this);
        Connector results[] = new Connector[connectors.length + ];
        System.arraycopy(connectors, , results, , connectors.length);
        results[connectors.length] = connector;
        connectors = results;
        if (initialized) {
            try {
                connector.initialize();
            } catch (LifecycleException e) {
                e.printStackTrace(System.err);
            }
        }
        if (started && (connector instanceof Lifecycle)) {
            try {
                ((Lifecycle) connector).start();
            } catch (LifecycleException e) {
                ;
            }
        }
        support.firePropertyChange("connector", null, connector);
    }
}
           

Server 代表整個容器

提供接口讓其它程式能夠通路到 Service 集合、同時要維護它所包含的所有 Service 的生命周期,包括如何初始化、如何結束服務、如何查詢 Service等等,支援className,port,shutdown三個公共屬性。

StandardServer.addService

public void addService(Service service) {
    service.setServer(this);
    synchronized (services) {
        Service results[] = new Service[services.length + ];
        System.arraycopy(services, , results, , services.length);
        results[services.length] = service;
        services = results;
        if (initialized) {
            try {
                service.initialize();
            } catch (LifecycleException e) {
                e.printStackTrace(System.err);
            }
        }
        if (started && (service instanceof Lifecycle)) {
            try {
                ((Lifecycle) service).start();
            } catch (LifecycleException e) {
                ;
            }
        }
        support.firePropertyChange("service", null, service);
    }
}
           

Servlet 容器 Container

Tomcat 體系結構、關鍵元件及生命周期管理
  • Engine 表示一個Servlet引擎,它可以包含一個或多個子容器,比如Host或者Context容器;
  • Host 表示一台虛拟的主機,它可以包含一系列Context容器;
  • Context 表示一個唯一的ServletContext,一個 Context 對應一個 Web 工程,它可以包含一個 或多個Wrapper容器;
  • Wrapper 表示一個獨立的Servlet定義,即Wrapper本質就是對Servlet進行了一層包裝。

四種容器裝配方法:

Engine 和 Host 在 tomcat 的 conf/server.xml 中配置;

Context有三種配置方法:

1. 從檔案中配置:

- tomcat 的 conf/server.xml 中的 Context 标簽(tomcat重新開機時重新加載);

- conf/context.xml:所有應用的Context公共配置檔案,對所有的應用都起作用;

- conf/[enginename]/[hostname]/context.xml.default(在對應的host中共享);

- conf/[enginename]/[hostname]/appname.xml:*為應用名稱;

- 應用自己的 $CATALINA_BASE/webapps/[webappname]/META-INF/context.xml

2. 将WAR應用直接放到host目錄下,tomcat會自動查找并添加到host中;

3. 将應用檔案夾放到host目錄下。

Wrapper 的配置就是在 web.xml 中配置的 servlet,一個 servlet 對應一個 wrapper,conf/web.xml 中配置全局的 Wrapper。例如:

<servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup></load-on-startup>
    </servlet>
           

四種容器類圖關系

Tomcat 體系結構、關鍵元件及生命周期管理

tomcat的生命周期管理

Tomcat 通過 org.apache.catalina.Lifecycle 接口統一管理生命周期。所有有生命周期的元件都要實作該接口。該接口一共做四件事:

  • 定義LifecycleEvent事件的13種type屬性,區分元件發出LifecycleEvent事件時的狀态;
  • 定義三個管理事件監聽器的方法:addLifecycleListener、find、remove;
  • 定義四個生命周期的方法:init、start、stop、destroy;
  • 定義了擷取目前狀态的方法:getState和getStateName(傳回String類型的狀态名字,主要用于JMX中)
Tomcat 體系結構、關鍵元件及生命周期管理

Lifecycle 接口的方法的實作都在其它元件中,元件的生命周期由包含它的父元件控制,是以它的 Start 方法自然就是調用它下面的元件的 Start 方法,Stop 方法也是一樣。如在 Server 中 Start 方法會調用 Service 元件的 Start 方法,Server 的 Start 方法代碼如下:

StandardServer.Start

//事實上,四個生命周期管理方法都需要判斷目前狀态和要處理的方法是否比對,不比對則執行相應的方法使之比對;同時,執行過程中需要修改該元件的生命周期狀态。

public void start() throws LifecycleException {
    if (started) {
        log.debug(sm.getString("standardServer.start.started"));
        return;
    }
    lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    lifecycle.fireLifecycleEvent(START_EVENT, null);
    started = true;
    synchronized (services) {
        for (int i = ; i < services.length; i++) {
            if (services[i] instanceof Lifecycle)
                ((Lifecycle) services[i]).start();
        }
    }
    lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}
           

StandardServer.Stop

public void stop() throws LifecycleException {
    if (!started)
        return;
    lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
    lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    started = false;
    for (int i = ; i < services.length; i++) {
        if (services[i] instanceof Lifecycle)
            ((Lifecycle) services[i]).stop();
    }
    lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}
           

附錄檔案

附錄1 \WEB-INF\uCom-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">

    <!--增加本地和Controller掃描路徑-->
    <context:component-scan base-package="com.urepCompany.**.controller" >
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"
          p:messageConverters-ref="messageConverters"/>
    <util:list id="messageConverters">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
    </util:list>

    <bean id="base.webUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/base/commonImageFileuploadFrameController.do_">repCompany.CommonImageFileuploadFrameController</prop>
                <prop key="/base/commonImageDownloadFrameController.do_">repCompany.CommonImageDownloadController</prop>
                <prop key="/base/getMilliTime.do_">repCompany.GetMilliTimeController</prop>
            </props>
        </property>
    </bean>
</beans>
           

參考文獻

http://tomcat.apache.org/tomcat-6.0-doc/index.html

https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/catalina/Lifecycle.html

http://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/

http://stackoverflow.com/questions/18578143/about-multiple-containers-in-spring-framework

https://yq.aliyun.com/articles/20172