Tomcat啟動流程分析


來源

本文整理自 <Tomcat內核設計剖析>、<Tomcat結構解析> 加上自己的理解、源碼來自 Tomcat8.5 版本

Tomcat啟動流程分析

Init流程時序圖

Start流程時序圖

Bootstrap

// org.apache.catalina.startup.Bootstrap
public static void main(String args[]) {
    if (daemon == null) {
        // 先創建一個  bootstrap 實例
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.init();
        } catch (Throwable t) {
            return;
        }
        daemon = bootstrap;
    } else {
        Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
    }

    try {
        // 默認執行 start 方法
        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);
            // 反射調用 catalinaDaemon#load 方法,根據server.xml 創建服務
            daemon.load(args);
            // 反射調用 catalinaDaemon#start 方法,啟動服務
            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);
        }
    }
}

/**
     * Initialize daemon.
     * @throws Exception Fatal initialization error
     */
public void init() throws Exception {
    // 初始化類加載器
    initClassLoaders();
    Thread.currentThread().setContextClassLoader(catalinaLoader);
    SecurityClassLoad.securityClassLoad(catalinaLoader);
    Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
    // 反射生成 Catalina 類
    Object startupInstance = startupClass.getConstructor().newInstance();
    String methodName = "setParentClassLoader";
    Class<?> paramTypes[] = new Class[1];
    paramTypes[0] = Class.forName("java.lang.ClassLoader");
    Object paramValues[] = new Object[1];
    paramValues[0] = sharedLoader;
    // 反射調用 Catalina 類的 setParentClassLoader 方法。
    Method method =
        startupInstance.getClass().getMethod(methodName, paramTypes);
    method.invoke(startupInstance, paramValues);
    catalinaDaemon = startupInstance;
}

private void initClassLoaders() {
    try {
        commonLoader = createClassLoader("common", null);
        if( commonLoader == null ) {
            commonLoader=this.getClass().getClassLoader();
        }
        catalinaLoader = createClassLoader("server", commonLoader);
        sharedLoader = createClassLoader("shared", commonLoader);
    } catch (Throwable t) {
        System.exit(1);
    }
}

流程圖

Catalina

// org.apache.catalina.startup.Catalina

// 設置 await值,會在start方法中服務器啟動完成后來判斷是否進入等待狀態
// true :后續會去監聽8005端口
// false:運行完成后就退出
public void setAwait(boolean b) {
    await = b;
}

public void load() {
    // 已經加載就返回
    if (loaded) { return; }
    // 設置加載狀態
    loaded = true;
    // 在解析之前,設置一些系統屬性
    initNaming();
    // 通過 digester 解析 server.xml 配置文件
    Digester digester = createStartDigester();
    InputSource inputSource = null;
    InputStream inputStream = null;
    File file = null;
    try {
        try {
            // 默認指定了 conf/server.xml 
            file = configFile();
            inputStream = new FileInputStream(file);
            inputSource = new InputSource(file.toURI().toURL().toString());
        }
        if (inputStream == null) {
            try {
                inputStream = getClass().getClassLoader()
                    .getResourceAsStream(getConfigFile());
                inputSource = new InputSource
                    (getClass().getClassLoader()
                     .getResource(getConfigFile()).toString());
            }
        }
        if (inputStream == null) {
            // 嘗試加載 server-embed.xml 
            try {
                inputStream = getClass().getClassLoader()
                    .getResourceAsStream("server-embed.xml");
                inputSource = new InputSource
                    (getClass().getClassLoader()
                     .getResource("server-embed.xml").toString());
            }
        }
        // 依舊找不到文件,返回
        if (inputStream == null || inputSource == null) {
            return;
        }
        try {
            inputSource.setByteStream(inputStream);
            digester.push(this);
            // 解析 xml
            digester.parse(inputSource);
        }
    }
    getServer().setCatalina(this);
    // 在 static中定義,
    getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
    getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    // Replace System.out and System.err with a custom PrintStream
    initStreams();
    // 創建 Server
    getServer().init();
}
/*
Digester 查相關資料:Java解析xml主要由DOM4J(一次讀取到內存並解析)、SAX(一次解析一部分),digester本身采用SAX的解析方式,並提供了一層包裝,對使用者更加友好,后來獨立出來成為apache的Commons下面的[一個單獨的子項目](http://commons.apache.org/proper/commons-digester/)。
*/

public void start() {
    if (getServer() == null) {
        load();
    }
    if (getServer() == null) {
        return;
    }
    try {
        // 調用Server的start方法啟動服務器
        getServer().start();
    } catch (LifecycleException e) {
        getServer().destroy();
        return;
    }
    // 注冊 關閉 鈎子方法
    if (useShutdownHook) {
        if (shutdownHook == null) {
            shutdownHook = new CatalinaShutdownHook();
        }
        Runtime.getRuntime().addShutdownHook(shutdownHook);
        LogManager logManager = LogManager.getLogManager();
        if (logManager instanceof ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                false);
        }
    }
    // 此處判斷 主線程是否await
    if (await) {
        // 在 StandardServer 中調用,用來監聽 8005 端口,
        // 收到 SHUTDOWN 命令關閉 Server
        await();
        stop();
    }
}

Init流程圖

Start流程圖

StandardServer

@Override
protected void initInternal() throws LifecycleException {
    super.initInternal();
    // 注冊全局 String cache
    onameStringCache = register(new StringCache(), "type=StringCache");
    // 注冊 MBeanFactory
    MBeanFactory factory = new MBeanFactory();
    factory.setContainer(this);
    onameMBeanFactory = register(factory, "type=MBeanFactory");
    // 注冊命名資源
    globalNamingResources.init();

    // Populate the extension validator with JARs from common and shared
    // class loaders
    if (getCatalina() != null) {
        ClassLoader cl = getCatalina().getParentClassLoader();
        while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
            if (cl instanceof URLClassLoader) {
                URL[] urls = ((URLClassLoader) cl).getURLs();
                for (URL url : urls) {
                    if (url.getProtocol().equals("file")) {
                        File f = new File (url.toURI());
                        if (f.isFile() &&
                            f.getName().endsWith(".jar")) {
                            ExtensionValidator.addSystemResource(f);
                        }
                    }
                }
            }
            cl = cl.getParent();
        }
    }
    // 初始化定義的所有 Service
    for (int i = 0; i < services.length; i++) {
        services[i].init();
    }
}

@Override
protected void startInternal() throws LifecycleException {
	// 設置狀態
    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    // 觸發事件
    setState(LifecycleState.STARTING);
    globalNamingResources.start();
    synchronized (servicesLock) {
        for (int i = 0; i < services.length; i++) {
            services[i].start();
        }
    }
}

@Override
public void await() {
    try {
        // port 默認 8005
        awaitSocket = new ServerSocket(port, 1,
                     InetAddress.getByName(address));
    } catch (IOException e) {
        return;
    }
    // 匹配 SHUTDOWN 命令,用來關閉服務器
    boolean match = command.toString().equals(shutdown);
    if (match) {
        break;
    }
    
    ServerSocket serverSocket = awaitSocket;
    awaitThread = null;
    awaitSocket = null;

    // 關閉Server socket並返回
    if (serverSocket != null) {
        serverSocket.close();
    }
}

StandardService

@Override
protected void initInternal() throws LifecycleException {
    super.initInternal();
	// Engine初始化,一個Service對應一個Engine
    if (engine != null) {
        engine.init();
    }
    // 初始化Executor,默認 不會執行
    for (Executor executor : findExecutors()) {
        if (executor instanceof JmxEnabled) {
            ((JmxEnabled) executor).setDomain(getDomain());
        }
        executor.init();
    }
    // 初始化 MapperListener , 默認 LifecycleMBeanBase.java 
    mapperListener.init();
    // 初始化 Connector,server.xml 配置的 Connector
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            connector.init();
        }
    }
}

@Override
protected void startInternal() throws LifecycleException {
    setState(LifecycleState.STARTING);
    if (engine != null) {
        synchronized (engine) {
            engine.start();
        }
    }
    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }
    mapperListener.start();
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            if (connector.getState() != LifecycleState.FAILED) {
                connector.start();
            }
        }
    }
}

ContainerBase

​ 是容器的抽象父類,定義了容器生命周期中公共方法。Engine、Host、Context、Wrapper繼承此父類。

@Override
protected void initInternal() throws LifecycleException {
    // 創建 線程池
    BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
    startStopExecutor = new ThreadPoolExecutor(
        getStartStopThreadsInternal(),
        getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
        startStopQueue,
        new StartStopThreadFactory(getName() + "-startStop-"));
    startStopExecutor.allowCoreThreadTimeOut(true);
    super.initInternal();
}

@Override
protected synchronized void startInternal() throws LifecycleException {
    // 如果有 Cluster和 Realm則調用其 start 方法
    Cluster cluster = getClusterInternal();
    if (cluster instanceof Lifecycle) {
        ((Lifecycle) cluster).start();
    }
    Realm realm = getRealmInternal();
    if (realm instanceof Lifecycle) {
        ((Lifecycle) realm).start();
    }
    // 通過 Future 調用所有子容器的 start方法
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    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 {
            // 獲取子容器 start 方法結果
            result.get();
        } catch (Exception e) {
            log.error(sm.getString("containerBase.threadedStartFailed"), e);
            fail = true;
        }
    }
    if (fail) {
        throw new LifecycleException(
            sm.getString("containerBase.threadedStartFailed"));
    }
    // 啟用管道,后面介紹到
    if (pipeline instanceof Lifecycle)
        ((Lifecycle) pipeline).start();
    // 設置狀態值
    setState(LifecycleState.STARTING);
    // 啟動后台線程,日志輸出等工作,
    threadStart();
}

// 開啟后台線程,定時檢查 session 超時、
protected void threadStart() {
    if (thread != null)
        return;
    if (backgroundProcessorDelay <= 0)
        return;
    threadDone = false;
    String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
    thread = new Thread(new ContainerBackgroundProcessor(), threadName);
    thread.setDaemon(true);
    thread.start();
}

// 內部類 ContainerBackgroundProcessor, 默認 10s一次
// 在 StandardEngine 構造函數中定義
protected void processChildren(Container ContainerBase.this) {
    container.backgroundProcess();
    Container[] children = container.findChildren();
    for (int i = 0; i < children.length; i++) {
        if (children[i].getBackgroundProcessorDelay() <= 0) {
            processChildren(children[i]);
        }
    }
}

@Override
public void backgroundProcess() {
    if (!getState().isAvailable())
        return;
    Cluster cluster = getClusterInternal();
    if (cluster != null) {
        cluster.backgroundProcess();
    }
    Realm realm = getRealmInternal();
    if (realm != null) {
        realm.backgroundProcess();
    }
    Valve current = pipeline.getFirst();
    while (current != null) {
        current.backgroundProcess();
        current = current.getNext();
    }
    fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
}

// LifecycleBase
protected void fireLifecycleEvent(String type, Object data) {
    LifecycleEvent event = new LifecycleEvent(this, type, data);
    for (LifecycleListener listener : lifecycleListeners) {
        listener.lifecycleEvent(event);
    }
}

// 看一下 HostConfig 的 lifecycleEvent 方法
@Override
public void lifecycleEvent(LifecycleEvent event) {
    if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
        // 是否自動部署
        check();
    } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
        beforeStart();
    } else if (event.getType().equals(Lifecycle.START_EVENT)) {
        start();
    } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
        stop();
    }
}

容器的作用

​ Container的4個容器是逐層包含的關系。它們之間的關系如下圖:

1、Engine:用來管理多個站點,一個Service最多只能有一個Engine。

2、Host:代表一個站點,通過配置Host可以添加站點。

3、Context:代表一個應用程序,對應一個WEB-INF目錄。

4、Wrapper:每個Wrapper封裝一個Servlet。

容器的配置

1、

<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
    <!-- Define an AJP 1.3 Connector on port 8009 -->
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

    <Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
      </Host>
    </Engine>
  </Service>
</Server>
  • Server 在 8005端口監聽關閉命令“SHUTDOWN”;
  • Server 中定義了一個 Catalina的Service;
  • Service 中定義了兩個Connector:
    • 一個是HTTP協議;
    • 一個是AJP協議(用於集成);
  • Service 中還定義了了一個Catalina的Engine;
  • Engine 中定義了 localhost 的 Host;
    • defaultHost:請求的域名如果在所有的Host的name和Alias中都找不到使用的默認值
  • Host:
    • name:表示域名;
    • appBase:站點的位置;
    • unpackWARS:是否自動解壓war包;
    • autoDeploy:是否自動部署;
    • 子標簽: excelib.com :給localhost定義別名;

2、Context通過文件配置的方式一共有5個位置可以配置:

  • conf/server.xml中的Context標簽;
  • conf/[enginename]/[hostname]/目錄下以應用命名的 xml 文件。
  • 應用自己的 /META-INT/context.xml;
  • conf/context.xml 文件
  • conf/[enginename]/[hostname]/context.xml.default文件;

3、前三個用於配置單獨的應用,后面2種是Context共享的。第4種是 整個 Tomcat 共享,第5種配置的內容在對應的站點(Host)中共享。第1種方式只有在Tomcat重啟才會重新加載,不推薦使用。

<!-- 
	用於全局配置
	The contents of this file will be loaded for each web application 
-->
<Context>

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
</Context>

4、Wrapper的配置,在web.xml中配置的Servlet,一個Servlet對應一個Wrapper、可以在 conf/web.xml 中配置全局的 Wrapper,處理 Jsp的 JspServlet的配置等。

<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>3</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>jsp</servlet-name>
    <url-pattern>*.jsp</url-pattern>
    <url-pattern>*.jspx</url-pattern>
</servlet-mapping>

<!--配置了 session 超時時間-->
<session-config>
    <session-timeout>30</session-timeout>
</session-config>

<!-- 很多 mime 類型 -->
<mime-mapping>
</mime-mapping>

StandardEngine

public StandardEngine() {
    super();
    // pipeline 設置 basicValve
    pipeline.setBasic(new StandardEngineValve());
    setJvmRoute(System.getProperty("jvmRoute"));
    // 設置等待時間 10
    backgroundProcessorDelay = 10;
}

@Override
protected void initInternal() throws LifecycleException {
    // 沒有定義 Realm ,設置一個 NullRealm,權限訪問。
    getRealm();
    super.initInternal();
}

@Override
protected synchronized void startInternal() throws LifecycleException {
    super.startInternal();
}

StandardHost

public StandardHost() {
    super();
    // 設置 BasicValve
    pipeline.setBasic(new StandardHostValve());
}

@Override
protected synchronized void startInternal() throws LifecycleException {
    // 設置 error Valve
    String errorValve = getErrorReportValveClass();
    if ((errorValve != null) && (!errorValve.equals(""))) {
        try {
            boolean found = false;
            Valve[] valves = getPipeline().getValves();
            for (Valve valve : valves) {
                if (errorValve.equals(valve.getClass().getName())) {
                    found = true;
                    break;
                }
            }
            if(!found) {
                // 綁定 errorValve
                Valve valve =
                    (Valve) Class.forName(errorValve).getConstructor().newInstance();
                getPipeline().addValve(valve);
            }
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
        }
    }
    super.startInternal();
}

StandardContext

public StandardContext() {
    super();
    // 設置 BasicValve
    pipeline.setBasic(new StandardContextValve());
    // 廣播通知
    broadcaster = new NotificationBroadcasterSupport();
    if (!Globals.STRICT_SERVLET_COMPLIANCE) {
        resourceOnlyServlets.add("jsp");
    }
}

@Override
protected synchronized void startInternal() throws LifecycleException {
    // Send j2ee.state.starting notification
    if (this.getObjectName() != null) {
        Notification notification = new Notification("j2ee.state.starting",
                                                     this.getObjectName(), sequenceNumber.getAndIncrement());
        broadcaster.sendNotification(notification);
    }

    setConfigured(false);
    boolean ok = true;

    // namingResources 啟動
    if (namingResources != null) {
        namingResources.start();
    }

    // Post work directory
    postWorkDirectory();

    // Add missing components as necessary
    if (getResources() == null) {   // (1) Required by Loader
        try {
            setResources(new StandardRoot(this));
        } catch (IllegalArgumentException e) {
            ok = false;
        }
    }
    if (ok) {
        // 加載 /WEB-INF/classes/META-INF/resources 目錄下資源
        resourcesStart();
    }
    // 設置加載器
    if (getLoader() == null) {
        WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
        webappLoader.setDelegate(getDelegate());
        setLoader(webappLoader);
    }

    // cookie 處理器
    if (cookieProcessor == null) {
        cookieProcessor = new Rfc6265CookieProcessor();
    }

    // 初始化 CharsetMapper
    getCharsetMapper();

    // 驗證 /META-INF/MANIFEST.MF
    boolean dependencyCheck = true;
    try {
        dependencyCheck = ExtensionValidator.validateApplication
            (getResources(), this);
    } catch (IOException ioe) {
        dependencyCheck = false;
    }

    // // 驗證失敗, application 不可用
    if (!dependencyCheck) {
        ok = false;
    }

    // catalina.useNaming 環境變量
    String useNamingProperty = System.getProperty("catalina.useNaming");
    if ((useNamingProperty != null)
        && (useNamingProperty.equals("false"))) {
        useNaming = false;
    }

    if (ok && isUseNaming()) {
        if (getNamingContextListener() == null) {
            NamingContextListener ncl = new NamingContextListener();
            ncl.setName(getNamingContextName());
            ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
            // 注冊 LifecycleListener
            addLifecycleListener(ncl);
            setNamingContextListener(ncl);
        }
    }

    // Binding thread
    ClassLoader oldCCL = bindThread();

    try {
        if (ok) {
            // Start our subordinate components, if any
            Loader loader = getLoader();
            if (loader instanceof Lifecycle) {
                ((Lifecycle) loader).start();
            }

            // since the loader just started, the webapp classloader is now
            // created.
            setClassLoaderProperty("clearReferencesRmiTargets",
                                   getClearReferencesRmiTargets());
            setClassLoaderProperty("clearReferencesStopThreads",
                                   getClearReferencesStopThreads());
            setClassLoaderProperty("clearReferencesStopTimerThreads",
                                   getClearReferencesStopTimerThreads());
            setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread",
                                   getClearReferencesHttpClientKeepAliveThread());
            setClassLoaderProperty("clearReferencesObjectStreamClassCaches",
                                   getClearReferencesObjectStreamClassCaches());

            // By calling unbindThread and bindThread in a row, we setup the
            // current Thread CCL to be the webapp classloader
            unbindThread(oldCCL);
            oldCCL = bindThread();

            // Initialize logger again. Other components might have used it
            // too early, so it should be reset.
            logger = null;
            getLogger();

            Realm realm = getRealmInternal();
            if(null != realm) {
                if (realm instanceof Lifecycle) {
                    ((Lifecycle) realm).start();
                }

                // Place the CredentialHandler into the ServletContext so
                // applications can have access to it. Wrap it in a "safe"
                // handler so application's can't modify it.
                CredentialHandler safeHandler = new CredentialHandler() {
                    @Override
                    public boolean matches(String inputCredentials, String storedCredentials) {
                        return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials);
                    }

                    @Override
                    public String mutate(String inputCredentials) {
                        return getRealmInternal().getCredentialHandler().mutate(inputCredentials);
                    }
                };
                context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler);
            }

            // 調用事件
            fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);

            // 在不可用的時候,啟動子容器
            for (Container child : findChildren()) {
                if (!child.getState().isAvailable()) {
                    child.start();
                }
            }

            // pipeline 的啟動
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).start();
            }

            // 獲取集群管理器
            Manager contextManager = null;
            Manager manager = getManager();
            if (manager == null) {
                if ( (getCluster() != null) && distributable) {
                    try {
                        contextManager = getCluster().createManager(getName());
                    } catch (Exception ex) {
                        ok = false;
                    }
                } else {
                    contextManager = new StandardManager();
                }
            }

            // 配置默認管理器
            if (contextManager != null) {
                setManager(contextManager);
            }
			// 注冊管理器
            if (manager!=null && (getCluster() != null) && distributable) {
                getCluster().registerManager(manager);
            }
        }

        if (!getConfigured()) {
            ok = false;
        }

        // 將資源 放到 servlet Context 中
        if (ok)
            getServletContext().setAttribute
            (Globals.RESOURCES_ATTR, getResources());

        if (ok ) {
            if (getInstanceManager() == null) {
                javax.naming.Context context = null;
                if (isUseNaming() && getNamingContextListener() != null) {
                    context = getNamingContextListener().getEnvContext();
                }
                Map<String, Map<String, String>> injectionMap = buildInjectionMap(
                    getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources());
                setInstanceManager(new DefaultInstanceManager(context,
                                                              injectionMap, this, this.getClass().getClassLoader()));
            }
            getServletContext().setAttribute(
                InstanceManager.class.getName(), getInstanceManager());
            InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager());
        }

        // Create context attributes that will be required
        if (ok) {
            getServletContext().setAttribute(
                JarScanner.class.getName(), getJarScanner());
        }

        // 設置上下文 init 參數
        mergeParameters();

        // Call ServletContainerInitializers
        for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
             initializers.entrySet()) {
            try {
                entry.getKey().onStartup(entry.getValue(),
                                         getServletContext());
            } catch (ServletException e) {
                log.error(sm.getString("standardContext.sciFail"), e);
                ok = false;
                break;
            }
        }

        // 調用 listener
        if (ok) {
            if (!listenerStart()) {
                ok = false;
            }
        }
        // Check constraints for uncovered HTTP methods
        // Needs to be after SCIs and listeners as they may programmatically
        // change constraints
        if (ok) {
            checkConstraintsForUncoveredMethods(findConstraints());
        }
        try {
            // Start manager
            Manager manager = getManager();
            if (manager instanceof Lifecycle) {
                ((Lifecycle) manager).start();
            }
        } catch(Exception e) {
            ok = false;
        }
        // filter調用
        if (ok) {
            if (!filterStart()) {
                ok = false;
            }
        }
        // 初始化 Servlet,如果配置了 LoadOnStartUp
        if (ok) {
            if (!loadOnStartup(findChildren())){
                ok = false;
            }
        }
        // 啟動后台線程
        super.threadStart();
    } finally {
        unbindThread(oldCCL);
    }
	// 資源回收
    getResources().gc();

    if (!ok) {
        setState(LifecycleState.FAILED);
    } else {
        setState(LifecycleState.STARTING);
    }
}

StandardWrapper

public StandardWrapper() {
    super();
    swValve = new StandardWrapperValve();
    // 設置 BasicValve
    pipeline.setBasic(swValve);
    broadcaster = new NotificationBroadcasterSupport();
}

@Override
protected synchronized void startInternal() throws LifecycleException {

    // Send j2ee.state.starting notification
    if (this.getObjectName() != null) {
        Notification notification = new Notification("j2ee.state.starting",
                                                     this.getObjectName(),
                                                     sequenceNumber++);
        broadcaster.sendNotification(notification);
    }
    super.startInternal();
    setAvailable(0L);
    // Send j2ee.state.running notification
    if (this.getObjectName() != null) {
        Notification notification =
            new Notification("j2ee.state.running", this.getObjectName(),
                             sequenceNumber++);
        broadcaster.sendNotification(notification);
    }
}

StandardPipeline

@Override
protected void initInternal() { }

@Override
protected synchronized void startInternal() throws LifecycleException {
    Valve current = first;
    if (current == null) {
        current = basic;
    }
    while (current != null) {
        if (current instanceof Lifecycle)
            ((Lifecycle) current).start();
        current = current.getNext();
    }
    setState(LifecycleState.STARTING);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM