美文网首页Tomcat
Tomcat start过程分析

Tomcat start过程分析

作者: 晴天哥_王志 | 来源:发表于2018-10-19 10:16 被阅读151次

    开篇

     这篇文章主要是把Tomcat的start启动过程的时序图和源码进行结合,加深一下印象,同时在分析源码过程中会分析下Tomcat的代码设计结构供自己提升抽象能力,想更好的阅读这部分代码提前了解以下问题。

    • 1、如果代码上无法直接串联起来那么就通过源码debug发现调用栈。
    • 2、容器类的启动过程跟类的继承实现关系非常大所以需要好好研究基类。
    • 3、容器的start过程类似于串联调用的过程,这点有助于理解代码逻辑。
    • 4、每个容器的启动过程不做容器启动细节分析,这部分分析后续补充。

    Tomcat启动过程时序图

    Tomcat 启动过程流程图

    说明:

    • Tomcat的整个服务器启动包括初始化过程和启动过程
    • 该篇文章主要是分析start()初始化过程

    Tomcat启动过程 - Bootstrap启动

    • Bootstrap通过反射调用Catalina的start()接口启动Catalina对象。
    public final class Bootstrap {
    
        public void start()
            throws Exception {
            if( catalinaDaemon==null ) init();
    
            Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
            method.invoke(catalinaDaemon, (Object [])null);
    
        }
    }
    

    Tomcat启动过程 - Catalina启动

    • Catalina调用StandardServer的基类LifecycleBase的start()接口启动StandardService。
    public class Catalina {
    
        public void start() {
    
            if (getServer() == null) {
                load();
            }
    
            // 启动Server的服务
            try {
                getServer().start();
            } catch (LifecycleException e) {
                log.fatal(sm.getString("catalina.serverStartFail"), e);
                try {
                    getServer().destroy();
                } catch (LifecycleException e1) {
                    log.debug("destroy() failed for failed Server ", e1);
                }
                return;
            }
    
            // 省略相关代码
        }
    }
    

    Tomcat启动过程 - Server启动

    • StandardServer的启动过程通过调用基类LifecycleBase的start()接口

    • StandardServer的内部通过调用startInternal()启动自身。

    • StandardServer的内部通过services[i].start()启动Service对象。


      StandardServer
    public final class StandardServer extends LifecycleMBeanBase implements Server {
    
        @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();
                }
            }
        }
    }
    

    Tomcat启动过程 - Service启动

    • StandardService的启动过程通过调用基类LifecycleBase的start()接口

    • StandardService的内部通过调用startInternal()启动自身。

    • StandardServer的内部通过engine.start()启动Engine对象。

    • StandardServer的内部通过executor.start()启动Executor对象。

    • StandardServer的内部通过mapperListener.start()启动MapperListener对象。

    • StandardServer的内部通过connector.start()启动Connector对象。

    StandardService
    public class StandardService extends LifecycleMBeanBase implements Service {
    
        @Override
        protected void startInternal() throws LifecycleException {
    
            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);
                    }
                }
            }
        }
    }
    

    Tomcat启动过程 - ContainerBase

    • ContainerBase的startInternal是所有容器父容器,内部启动过程都会执行。

    • ContainerBase的startInternal()方法内部负责启动Cluster对象。

    • ContainerBase的startInternal()方法内部负责启动Realm对象。

    • ContainerBase的startInternal()方法内部负责启动子容器Container对象。

    • ContainerBase的startInternal()方法内部负责处理链条pipeline对象。

    • ContainerBase的startInternal()方法内部负责处理启动线程threadStart。

    ContainerBase
    public interface Lifecycle {
    
        public static final String BEFORE_INIT_EVENT = "before_init";
        public static final String AFTER_INIT_EVENT = "after_init";
        public static final String START_EVENT = "start";
        public static final String BEFORE_START_EVENT = "before_start";
        public static final String AFTER_START_EVENT = "after_start";
        public static final String STOP_EVENT = "stop";
        public static final String BEFORE_STOP_EVENT = "before_stop";
        public static final String AFTER_STOP_EVENT = "after_stop";
        public static final String AFTER_DESTROY_EVENT = "after_destroy";
        public static final String BEFORE_DESTROY_EVENT = "before_destroy";
        public static final String PERIODIC_EVENT = "periodic";
        public static final String CONFIGURE_START_EVENT = "configure_start";
        public static final String CONFIGURE_STOP_EVENT = "configure_stop";
    
    
        public void addLifecycleListener(LifecycleListener listener);
        public LifecycleListener[] findLifecycleListeners();
        public void removeLifecycleListener(LifecycleListener listener);
        public void init() throws LifecycleException;
        public void start() throws LifecycleException;
        public void stop() throws LifecycleException;
        public void destroy() throws LifecycleException;
        public LifecycleState getState();
        public String getStateName();
    
        public interface SingleUse {
        }
    }
    
    
    public abstract class LifecycleBase implements Lifecycle {
    
        public final synchronized void init() throws LifecycleException {
            if (!state.equals(LifecycleState.NEW)) {
                invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
            }
    
            try {
                setStateInternal(LifecycleState.INITIALIZING, null, false);
                initInternal();
                setStateInternal(LifecycleState.INITIALIZED, null, false);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                setStateInternal(LifecycleState.FAILED, null, false);
                throw new LifecycleException(
                        sm.getString("lifecycleBase.initFail",toString()), t);
            }
        }
    
    
        protected abstract void initInternal() throws LifecycleException;
    
        @Override
        public final synchronized void start() throws LifecycleException {
    
            if (state.equals(LifecycleState.NEW)) {
                init();
            } else if (state.equals(LifecycleState.FAILED)) {
                stop();
            } else if (!state.equals(LifecycleState.INITIALIZED) &&
                    !state.equals(LifecycleState.STOPPED)) {
                invalidTransition(Lifecycle.BEFORE_START_EVENT);
            }
    
            try {
                setStateInternal(LifecycleState.STARTING_PREP, null, false);
                startInternal();
                if (state.equals(LifecycleState.FAILED)) {
                    // This is a 'controlled' failure. The component put itself into the
                    // FAILED state so call stop() to complete the clean-up.
                    stop();
                } else if (!state.equals(LifecycleState.STARTING)) {
                    // Shouldn't be necessary but acts as a check that sub-classes are
                    // doing what they are supposed to.
                    invalidTransition(Lifecycle.AFTER_START_EVENT);
                } else {
                    setStateInternal(LifecycleState.STARTED, null, false);
                }
            } catch (Throwable t) {
            }
        }
    
        protected abstract void startInternal() throws LifecycleException;
    }
    
    
    public abstract class ContainerBase extends LifecycleMBeanBase
            implements Container {
    
        @Override
        protected synchronized void startInternal() throws LifecycleException {
    
            // 启动下级组件
            logger = null;
            getLogger();
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).start();
            }
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).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])));
            }
    
            MultiThrowable multiThrowable = new MultiThrowable();
    
            for (Future<Void> result : results) {
                try {
                    result.get();
                } catch (Throwable e) {
                    log.error(sm.getString("containerBase.threadedStartFailed"), e);
                    multiThrowable.add(e);
                }
    
            }
            if (multiThrowable.size() > 0) {
                throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                        multiThrowable.getThrowable());
            }
    
            // 启动组件的处理链的组件
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).start();
            }
    
            // 设置容器处理状态
            setState(LifecycleState.STARTING);
    
            // 启动线程
            threadStart();
        }
    
    
        private static class StartChild implements Callable<Void> {
    
            private Container child;
    
            public StartChild(Container child) {
                this.child = child;
            }
    
            @Override
            public Void call() throws LifecycleException {
                child.start();
                return null;
            }
        }
    
    
        private static class StopChild implements Callable<Void> {
    
            private Container child;
    
            public StopChild(Container child) {
                this.child = child;
            }
    
            @Override
            public Void call() throws LifecycleException {
                if (child.getState().isAvailable()) {
                    child.stop();
                }
                return null;
            }
        }
    
    }
    

    Tomcat启动过程 - 容器对象的启动过程

    • 了解这个过程很重要,很重要,很重要!!!
    • 容器对象主要包括Engine、Host、Context、Wrapper。
    • 容器对象启动过程类似串联启动的过程,Engine启动带动Host,Host启动带动Context、Context启动带动Wrapper。
    • 容器都继承基类ContainerBase,通用的方法和执行过程都在该类中定义。

    Tomcat启动过程 - Engine启动

    • Engine启动过程主要是通过父类ContainerBase的startInternal()实现的。

    • ContainerBase的startInternal()通过startStopExecutor.submit(new StartChild(children[i]))启动host对象

    • Engine启动会调用ContainerBase的startInternal()启动自身的处理链pipeline。

    StandardEngine
    public class StandardEngine extends ContainerBase implements Engine {
    
        protected synchronized void startInternal() throws LifecycleException {
    
            // Log our server identification information
            if(log.isInfoEnabled())
                log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());
    
            // Standard container startup
            super.startInternal();
        }
    }
    

    Tomcat启动过程 - Host启动

    • Engine的StartChild()方法内部通过call()执行Host对象的启动。

    • Host对象继承自LifecycleBase类,start()方法会执行LifecycleBase的start()方法。

    • LifecycleBase的start()方法先判断Host的init()方法执行后再执行start()方法。

    • LifecycleBase的start()方法内部执行初始化Host的子容器也就是Context。

    StandardHost
    public class StandardHost extends ContainerBase implements Host {
    
        protected synchronized void startInternal() throws LifecycleException {
    
            // Set error report 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) {
                        Valve valve =
                            (Valve) Class.forName(errorValve).getConstructor().newInstance();
                        getPipeline().addValve(valve);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString(
                            "standardHost.invalidErrorReportValveClass",
                            errorValve), t);
                }
            }
            super.startInternal();
        }
    }
    

    Tomcat启动过程 - Context启动

    • Host的StartChild()方法内部通过call()执行Context对象的启动。

    • Context对象继承自LifecycleBase类,start()方法会执行LifecycleBase的start()方法。

    • LifecycleBase的start()方法先判断Context的init()方法执行后再执行start()方法。

    • LifecycleBase的start()方法内部初始化Context的子容器也就是Wrapper。

    StandardContext
    public class StandardContext extends ContainerBase
            implements Context, NotificationEmitter {
    
        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;
    
            // Currently this is effectively a NO-OP but needs to be called to
            // ensure the NamingResources follows the correct lifecycle
            if (namingResources != null) {
                namingResources.start();
            }
    
            // Post work directory
            postWorkDirectory();
    
            // Add missing components as necessary
            if (getResources() == null) {   // (1) Required by Loader
                if (log.isDebugEnabled())
                    log.debug("Configuring default Resources");
    
                try {
                    setResources(new StandardRoot(this));
                } catch (IllegalArgumentException e) {
                    log.error(sm.getString("standardContext.resourcesInit"), e);
                    ok = false;
                }
            }
            if (ok) {
                resourcesStart();
            }
    
            // 新建类加载器
            if (getLoader() == null) {
                WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
                webappLoader.setDelegate(getDelegate());
                setLoader(webappLoader);
            }
    
            // An explicit cookie processor hasn't been specified; use the default
            if (cookieProcessor == null) {
                cookieProcessor = new Rfc6265CookieProcessor();
            }
    
            // Initialize character set mapper
            getCharsetMapper();
    
            // Validate required extensions
            boolean dependencyCheck = true;
            try {
                dependencyCheck = ExtensionValidator.validateApplication
                    (getResources(), this);
            } catch (IOException ioe) {
                dependencyCheck = false;
            }
    
            if (!dependencyCheck) {
                ok = false;
            }
    
            // Reading the "catalina.useNaming" environment variable
            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());
                    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();
                        }
    
                        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);
                    }
    
                    // Notify our interested LifecycleListeners
                    fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
    
                    // Start our child containers, if not already started
                    for (Container child : findChildren()) {
                        if (!child.getState().isAvailable()) {
                            child.start();
                        }
                    }
    
                    if (pipeline instanceof Lifecycle) {
                        ((Lifecycle) pipeline).start();
                    }
    
                    // Acquire clustered manager
                    Manager contextManager = null;
                    Manager manager = getManager();
                    if (manager == null) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("standardContext.cluster.noManager",
                                    Boolean.valueOf((getCluster() != null)),
                                    Boolean.valueOf(distributable)));
                        }
                        if ( (getCluster() != null) && distributable) {
                            try {
                                contextManager = getCluster().createManager(getName());
                            } catch (Exception ex) {
                                log.error("standardContext.clusterFail", ex);
                                ok = false;
                            }
                        } else {
                            contextManager = new StandardManager();
                        }
                    }
    
                    // Configure default manager if none was specified
                    if (contextManager != null) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("standardContext.manager",
                                    contextManager.getClass().getName()));
                        }
                        setManager(contextManager);
                    }
    
                    if (manager!=null && (getCluster() != null) && distributable) {
                        //let the cluster know that there is a context that is distributable
                        //and that it has its own manager
                        getCluster().registerManager(manager);
                    }
                }
    
                if (!getConfigured()) {
                    log.error(sm.getString("standardContext.configurationFail"));
                    ok = false;
                }
    
                // We put the resources into the 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());
                }
    
                // Set up the context init params
                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;
                    }
                }
    
                // Configure and call application event listeners
                if (ok) {
                    if (!listenerStart()) {
                        log.error(sm.getString("standardContext.listenerFail"));
                        ok = false;
                    }
                }
    
                if (ok) {
                    checkConstraintsForUncoveredMethods(findConstraints());
                }
    
                try {
                    // Start manager
                    Manager manager = getManager();
                    if (manager instanceof Lifecycle) {
                        ((Lifecycle) manager).start();
                    }
                } catch(Exception e) {
                    ok = false;
                }
    
                // Configure and call application filters
                if (ok) {
                    if (!filterStart()) {
                        ok = false;
                    }
                }
    
                // Load and initialize all "load on startup" servlets
                if (ok) {
                    if (!loadOnStartup(findChildren())){
                        ok = false;
                    }
                }
    
                // Start ContainerBackgroundProcessor thread
                super.threadStart();
            } finally {
                // Unbinding thread
                unbindThread(oldCCL);
            }
    
            // Set available status depending upon startup success
            if (ok) {
                if (log.isDebugEnabled())
                    log.debug("Starting completed");
            } else {
            }
    
            startTime=System.currentTimeMillis();
    
            // Send j2ee.state.running notification
            if (ok && (this.getObjectName() != null)) {
                Notification notification =
                    new Notification("j2ee.state.running", this.getObjectName(),
                                     sequenceNumber.getAndIncrement());
                broadcaster.sendNotification(notification);
            }
    
            getResources().gc();
    
            // Reinitializing if something went wrong
            if (!ok) {
                setState(LifecycleState.FAILED);
            } else {
                setState(LifecycleState.STARTING);
            }
        }
    }
    

    Tomcat启动过程 - Wrapper启动

    • Context的StartChild()方法内部通过call()执行Wrapper对象的启动。

    • Wrapper对象继承自LifecycleBase类,start()方法会执行LifecycleBase的start()方法。

    • LifecycleBase的start()方法先判断Context的init()方法执行后再执行start()方法。

    StandardWrapper
    public class StandardWrapper extends ContainerBase
        implements ServletConfig, Wrapper, NotificationEmitter {
    
        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);
            }
    
            // Start up this component
            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);
            }
        }
    }
    

    Tomcat启动过程 - Connector启动

    • Connector继承自基类LifecycleMbeanBase类

    • StandardService调用Connector的start()方法启动Connector,最终调用Connector的startInternal()方法。

    • Connector的startInternal()方法串联执行protocolHandler的start()方法。


      image.png
    public class Connector extends LifecycleMBeanBase  {
    
        protected void startInternal() throws LifecycleException {
    
            // Validate settings before starting
            if (getPort() < 0) {
                throw new LifecycleException(sm.getString(
                        "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
            }
    
            setState(LifecycleState.STARTING);
    
            try {
                protocolHandler.start();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
            }
        }
    }
    

    Tomcat启动过程 - AbstractProtocol启动

    • AbstractProtocol的启动过程主要启动EndPoint的监听操作
    • EndPoint的启动过程就暂时不分析了。


      AbstractProtocol
    public abstract class AbstractProtocol<S> implements ProtocolHandler,
            MBeanRegistration {
    
        @Override
        public void start() throws Exception {
            if (getLog().isInfoEnabled()) {
                getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
            }
    
            endpoint.start();
    
            // Start async timeout thread
            asyncTimeout = new AsyncTimeout();
            Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
            int priority = endpoint.getThreadPriority();
            if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
                priority = Thread.NORM_PRIORITY;
            }
            timeoutThread.setPriority(priority);
            timeoutThread.setDaemon(true);
            timeoutThread.start();
        }
    }
    

    相关文章

      网友评论

        本文标题:Tomcat start过程分析

        本文链接:https://www.haomeiwen.com/subject/cezqzftx.html