(002)Tomcat源码分析

本文详细解析了Tomcat启动流程,从Bootstrap入口类开始,深入分析了类加载器的初始化、Catalina实例的创建、Server组件的初始化及启动过程。涵盖了容器组件如Service、Engine、Executor、Connector的初始化与启动细节。

1.Tomcat启动流程图
在这里插入图片描述

  • 首先从Tomcat启动入口类进行分析
    org.apache.catalina.startup.Bootstrap#main。main方法是整个tomcat启动时的入口。在main方法中,使用bootstrap.init()来初始化类加载器和创建Catalina实例,然后再启动Catalina线程。

【Bootstrap.java】

 /**
     * 2.运行的基础。(instance, init, load, start)
     * 2.1 创建Bootstrap(实例化)。
     * 2.2 检测运行命令。
     * 2.3 执行对应操作。
     * 2.4 Bootstrap初始化自身。(init自身。)
     * 2.5 加载(load)Catalina。
     *          2.5.1. Catalina初始化(init)Server
     *              2.5.1.1 Server去初始化(init)了Service。
     *                  2.5.1.1.1 Service去初始化(init)了Engine。
     *                  2.5.1.1.2 Service去初始化(init)了Executor。
     *                  2.5.1.1.3 Service去初始化(init)了Connector。
     *                      2.5.1.1.3.1 Connector去初始化了ProtocolHandler.
     *                          2.5.1.1.3.1.1 ProtocolHandler 初始化了EndPonit.
     *          2.5.2  Catalina(开启) start了Server。
     *              2.5.2.1 Server去开启(start)了Service。
     *                  2.5.1.1.1 Service去开启(start)了Engine。
     *                  2.5.1.1.2 Service去开启(start)了Executor。
     *                  2.5.1.1.3 Service去开启(start)了Connector。
     *                      2.5.1.1.3.1 Connector去开启(start)了ProtocolHandler.
     *                          2.5.1.1.3.1.1 ProtocolHandler 开启(start)了EndPonit.
     *
     * Main method and entry point when starting Tomcat via the provided
     * scripts.
     * 通过提供的脚本去执行入口方法.这是启动tomcat的入口。
     * @param args Command line arguments to be processed
     */
 public static void main(String args[]) {

        synchronized (daemonLock) {
            if (daemon == null) {
                // 在init()完成之前不要设置守护进程
                Bootstrap bootstrap = new Bootstrap();
                try {
                    //用于初始化容器相关,首先创建类加载器。
                    //然后通过反射创建org.apache.catalina.startup.Catalina实例
                    //@STEP1@
                    bootstrap.init();
                } catch (Throwable t) {
                    handleThrowable(t);
                    t.printStackTrace();
                    return;
                }
                //设置守护即引用Bootstrap
                daemon = bootstrap;
            } else {
                // When running as a service the call to stop will be on a new
                // thread so make sure the correct class loader is used to
                // prevent a range of class not found exceptions.
                Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
            }
        }
         /**
         * 此时daemon已经变成Catalina了。执行load方法其实是在执行Catalina的load方法。
         *   详见{@link Catalina#load}
         */
        try {
            //执行完init()方法后会判断启动参数的值,由于一般采用默认的启动方式。
            //所以main方法的参数是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 变成了Catalina。去初始化了Catalina。
                 * 并将Catalina.await设置为true.{@link Catalina#await()}
                 * 目的:在关闭窗口阻塞住监听关闭。将线程阻塞住。
                 * {@link Catalina#load()}
                 * Catalina.setAwait, Catalina.load, Catalina.start()。。。。。
                 */
                daemon.setAwait(true);
                //通过反射调用Cataline的load方法
                //@STEP2@
                daemon.load(args);
                /**
                 * 容器启动的入口。
                 * {@link Bootstrap#start()}
                 */
                //@STEP3@
                daemon.start();
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
            } 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);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            // Unwrap the Exception for clearer error reporting
            if (t instanceof InvocationTargetException &&
                    t.getCause() != null) {
                t = t.getCause();
            }
            handleThrowable(t);
            t.printStackTrace();
            System.exit(1);
        }
    }

我给上面的核心步骤做了标记,用了@STEP…@标识了,主要也对这几个进行说明。

【@STEP1@】

Bootstrap.java

  /**
     * 用于初始化容器相关,首先创建类加载器.
     * 然后通过反射创建org.apache.catalina.startup.Catalina实例:
     * @throws Exception
     */
    public void init() throws Exception {

        //初始化类加载器(Bootstrap 在启动的时候初始化了三种class loader:common、server、shared)
        initClassLoaders();

        Thread.currentThread().setContextClassLoader(catalinaLoader);

        SecurityClassLoad.securityClassLoad(catalinaLoader);

        // Load our startup class and call its process() method
        if (log.isDebugEnabled())
            log.debug("Loading startup class");
        Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.getConstructor().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;
        //通过反射调用了Catalina的setParentClassLoader方法来得到Cataline实例
        Method method =
            startupInstance.getClass().getMethod(methodName, paramTypes);
        method.invoke(startupInstance, paramValues);

        catalinaDaemon = startupInstance;
    }

bootstrap.init()方法,用于初始化容器相关,首先创建类加载器,然后通过反射创建org.apache.catalina.startup.Catalina实例。

【@STEP2@】

Bootstrap.java

 /**
     * 通过反射调用cataline的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;
        }
        
        //通过反射调用cataline的load方法
        Method method =
            catalinaDaemon.getClass().getMethod(methodName, paramTypes);
        if (log.isDebugEnabled()) {
            log.debug("Calling startup class " + method);
        }
        method.invoke(catalinaDaemon, param);
    }

真正调用的其实是下面的Catalina的load方法:

Catalina.java

 public void load() {
    //这里面源码很多行,就不全贴了,因为很多代码都是非业务的。
    //这边只把几个主要流程贴出来
    
    //创建一个Digester对象
    //(解析server.xml文件的解析器.即解析所有的组件)
    //@C-STEP1@
    Digester digester = createStartDigester();  
    //载入server.xml的流,用作后续解析用的
    inputSource.setByteStream(inputStream);  
    //压入栈顶
    digester.push(this);  
    //解析XML
    digester.parse(inputSource);  
    getServer().setCatalina(this);  
    // 获取 server,进行初始化。
    //使用模板方法设计模式,调用的是 StandardServer#initInternal
    getServer().init();  
 }

【C-STEP1】
Catalina.java

 protected Digester createStartDigester() {
        long t1=System.currentTimeMillis();
        //实例化一个Digester对象
        Digester digester = new Digester();
        //设置为false表示解析xml时不需要进行DTD的规则校验
        digester.setValidating(false);
        //是否进行节点设置规则校验.
        //如果xml中相应节点没有设置解析规则会在控制台显示提示信息
        digester.setRulesValidation(true);

        //将xml节点中的className作为假属性,不必调用默认的setter方法
        //(一般的节点属性在解析时将会以属性值作为入参调用该节点相应对象的setter方法,
        // 而className属性的作用是提示解析器用该属性的值来实例化对象)
        Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
        List<String> objectAttrs = new ArrayList<>();
        objectAttrs.add("className");
        fakeAttributes.put(Object.class, objectAttrs);
        List<String> contextAttrs = new ArrayList<>();
        contextAttrs.add("source");
        fakeAttributes.put(StandardContext.class, contextAttrs);
        digester.setFakeAttributes(fakeAttributes);
        digester.setUseContextClassLoader(true);

        // addObjectCreate方法的意思是碰到xml文件中的Server节点则创建一个StandardServer对象
        //第一个参数是匹配规则,如: <Server></Server>
        //第二个参数是创建默认对象的默认类
        //第三个参数是遇到匹配规则时用哪个属性来创建对象,如果没有则使用第二个参数传进去的默认
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        //根据Server节点中的属性信息调用相应属性的setter方法
        //以server.xml中的server节点来举例:
        // (会调用setPort、setShutdown方法,入参分别是8005、SHUTDOWN)
        digester.addSetProperties("Server");

        //这个方法作用是当解析完该标签之后,
        //则调用Digester栈里面比自己低一层的元素的methodName方法
        //将自己作为参数,并且把自己弹出栈
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");


        //【以下基本都一样,就不多做说明了,参考上面即可】
        //碰到Server节点下的GlobalNamingResources节点时取className属性值作为实例化类
        //实例化一个对象
        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/SSLHostConfig/OpenSSLConf",
                                 "org.apache.tomcat.util.net.openssl.OpenSSLConf");
        digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
        digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
                            "setOpenSslConf",
                            "org.apache.tomcat.util.net.openssl.OpenSSLConf");

        digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
                                 "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
        digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
        digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
                            "addCmd",
                            "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");

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

        long t2=System.currentTimeMillis();
        if (log.isDebugEnabled()) {
            log.debug("Digester for server.xml created " + ( t2-t1 ));
        }
        return digester;

    }
  • StandardServer#initInternal
    在这里插入图片描述
    遍历列表 services,调用 service.init() 方法,一个 Server 包含多个 Service。
  • StandardService#initInternal
    调用多个组件 engine、executor、connector 等组件的 init() 方法。
 /**
     * Invoke a pre-startup initialization. This is used to allow connectors
     * to bind to restricted ports under Unix operating environments.
     *
     * Service的初始化,通过包括:
     * 1. Engine的初始化工作。
     * 2. 部分线程池的初始化工作。
     * 3. MapperListener的初始化工作。
     * 4. 多个Connector的初始化。
     */
    @Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();
        /**
         * 初始化engine。可以点击进去看。
         * 我们可以猜到,后面肯定是Host,Context,Wrapper,Servlet.
         *  but,事实并不是如此。此时只是初始化过程.并不会初始化其余容器。其他几个容器的初始化操作是在start阶段完成的。
         *  {@link StandardEngine#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
        //初始化映射监听器。(Mapper作为从Service -->Mapper -->Adpter -->Container的链接。)
        mapperListener.init();

        // Initialize our defined Connectors
        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
                    /**
                     * Connector的初始化操作。
                     * {@link Connector#initInternal()}
                     */
                    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);
                }
            }
        }
    }
  • StandardEngine#initInternal
    调用父类 LifecycleMBeanBase 的 initInternal 方法。
  /**
     * 初始化方法。并没有去初始化后续容器。
     * @throws LifecycleException
     */
    @Override
    protected void initInternal() throws LifecycleException {
        // Ensure that a Realm is present before any attempt is made to start
        // one. This will create the default NullRealm if necessary.
        getRealm();
        /**
         * 调用父类的初始化。
         * 详见{@link ContainerBase#initInternal}
         */

        super.initInternal();
    }
  • StandardThreadExecutor#initInternal
    调用父类 LifecycleMBeanBase 的 initInternal 方法
   @Override
    protected void initInternal() throws LifecycleException {
        super.initInternal();
    }
  • Connector#initInternal
    设置适配器和进行端口绑定。
    ** CoyoteAdapter,适配器,用于将 Request 转换为 ServletRequest,this 为当前 connector;
    ** protocolHandler.init(),会调用 AbstractEndpoint 的 init() 方法,进行端口绑定。
 /**
     * Connector的初始化工作。
     * 1. 创建适配器。并设置协议处理器的适配器。
     * 2. 协议处理器的初始化工作()。
     * {@link ProtocolHandler}的中文注释。
     * @throws LifecycleException
     */
    @Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();

        // 初始化的时候设置我们的适配器。
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);

        // Make sure parseBodyMethodsSet has a default
        if (null == parseBodyMethodsSet) {
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoApr",
                    getProtocolHandlerClassName()));
        }
        if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
                protocolHandler instanceof AbstractHttp11JsseProtocol) {
            AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                    (AbstractHttp11JsseProtocol<?>) protocolHandler;
            if (jsseProtocolHandler.isSSLEnabled() &&
                    jsseProtocolHandler.getSslImplementationName() == null) {
                // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
            }
        }

        try {
            /**
             * 此处请点:
             * {@link AbstractHttp11JsseProtocol#init()}
             */
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
    }
  • AbstractProtocol#init
    主要为调用 AbstractEndpoint 的 init() 方法,进行端口绑定。
@Override
    public void init() throws Exception {
        if (getLog().isInfoEnabled()) {
            getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
        }

        if (oname == null) {
            // Component not pre-registered so register it
            oname = createObjectName();
            if (oname != null) {
                Registry.getRegistry(null, null).registerComponent(this, oname, null);
            }
        }

        if (this.domain != null) {
            rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
            Registry.getRegistry(null, null).registerComponent(
                    getHandler().getGlobal(), rgOname, null);
        }

        String endpointName = getName();
        endpoint.setName(endpointName.substring(1, endpointName.length()-1));
        endpoint.setDomain(domain);
        /** 初始化NioEndPoint。并绑定对应接口。
         *详见{@link NioEndpoint#bind()}
         */
        endpoint.init();
    }
  • AbstractEndpoint#init
    核心方法为 bind(),进行端口绑定。
public void init() throws Exception {
        if (bindOnInit) {
            bind();
            bindState = BindState.BOUND_ON_INIT;
        }
        if (this.domain != null) {
            // Register endpoint (as ThreadPool - historical name)
            oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
            Registry.getRegistry(null, null).registerComponent(this, oname, null);

            ObjectName socketPropertiesOname = new ObjectName(domain +
                    ":type=ThreadPool,name=\"" + getName() + "\",subType=SocketProperties");
            socketProperties.setObjectName(socketPropertiesOname);
            Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);

            for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                registerJmx(sslHostConfig);
            }
        }
    }

【@STEP3@】
Bootstrap.java

/**
     * Start the Catalina daemon.
     * 反射去调用Catalina的start方法。{@link Catalina#start()}
     * @throws Exception Fatal start error
     */
    public void start() throws Exception {
        if (catalinaDaemon == null) {
            init();
        }

        Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
        /**
         * 反射去调用Catalina的start方法。{@link Catalina#start()}
         */
        method.invoke(catalinaDaemon, (Object [])null);
    }

Catalina.java

/**
     *
     * {@link Bootstrap#start()}启动了此方法。
     * 目前的流程:
     * 1. BootStrap反射调用Cataline启动方法。
     * 2. Catalina启动方法去调用StandardServer的start方法。(点进去看。)
     *   {@link StandardServer#startInternal()}
     * 3.wait主线程。
     * Start a new server instance.
     *
     */
    public void start() {
        //不重要
        if (getServer() == null) {
            load();
        }
        //不重要
        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }
        //Start Server的开始时间 用于日志打印启动的具体时间。
        long t1 = System.nanoTime();

        // Start the new server 开启一个新的Server
        try {
            /**
             *
             * {@link LifecycleBase#start()} 注册生命周期事件给当前的所有lifecycleListeners内容。
             *  直接跳到下面:
             * {@link StandardServer#startInternal()} 分别执行。
             */
            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;
        }

        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
        }

        // Register shutdown hook
        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            Runtime.getRuntime().addShutdownHook(shutdownHook);

            // If JULI is being used, disable JULI's shutdown hook since
            // shutdown hooks run in parallel and log messages may be lost
            // if JULI's hook completes before the CatalinaShutdownHook()
            LogManager logManager = LogManager.getLogManager();
            if (logManager instanceof ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                        false);
            }
        }
        /**
         *
         */
        if (await) {
            await();
            stop();
        }
    }

StandardServer.java

/**
     *
     * 1.BootStrap反射调用Catalina的start。
     * 2.Catalina去调用了StandardServer的start方法。
     *  此方法就是Catalina的start方法。他会去调用StandardService的方法。
     *  {@link StandardService#startInternal()}
     * Start nested components ({@link Service}s) and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected void startInternal() throws LifecycleException {
        /**
         * 注册生命周期事件给当前所有监听器。
         */
        fireLifecycleEvent(CONFIGURE_START_EVENT, null);
        /**
         * 设置自身对应状态
         */
        setState(LifecycleState.STARTING);
        /**
         * NamingResourcesImpl
         * {@link NamingResourcesImpl#startInternal()}
         */
        globalNamingResources.start();

        // Start our defined Services
        /**
         * 注册所有的服务。
         * 1.{@link StandardService#startInternal()}
         */
        synchronized (servicesLock) {
            for (int i = 0; i < services.length; i++) {
               //调用Standardservice的启动
                services[i].start();
            }
        }
    }

StandardService.java

 /**
     *
     * 1.BootStrap反射调用Catalina的start。
     * 2.Catalina去调用了StandardServer的start方法。
     * 3.StandardServer调用StandardService的start方法。
     * 4.StandardService调用StandarEngine的start方法。
     *
     *
     * MapperListener start。
     * Connector start。
     * Start nested components ({@link Executor}s, {@link Connector}s and
     * {@link Container}s) and implement the requirements of
     * {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     * 启动:Executors, Connectors。
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @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
        /***
         * 1.{@link StandardEngine#startInternal()}
         */
        if (engine != null) {
            synchronized (engine) {
                /** Engin引擎启动。
                 * {@link StandardEngine#startInternal()}
                 */
                engine.start();
            }
        }

        synchronized (executors) {
            for (Executor executor: executors) {
                /**
                 * 线程池的启动。
                 */
                executor.start();
            }
        }
        /**
         * Connector和Container之间的映射器的启动。
         * {@link MapperListener#startInternal()}
         */
        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) {
                        /**
                         * {@link Connector#startInternal()}
                         */
                        connector.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }

ContainerBase.java

 /**
     1.BootStrap反射调用Catalina的start。
     * 2.Catalina去调用了StandardServer的start方法。
     * 3.StandardServer调用StandardService的start方法。
     * 4.StandardService调用StandarEngine的start方法。
     * 5.StandarEngine调用ContainerBase的start方法。(重点)
     * 6.ContainerBase的start方法:
     *          6.1 日志。
     *          6.2 安全。
     *          6.3 启动所有子容器(ChildList Future框架启动线程池去启动子结点)。启动子结点重点。
     *                  (Engin -> Host -> Context-> Wrapper 层级调用。
     *                      共享父类的方法,针对不同的容器处理不同。)
     *                      HostConfig类添加所有的Context结点。
     *                      然后在此类中进行启动。包括StandardContext结点。
     *                      StandardContext结点通过Web.xml文件,用ContextConfig添加了
     *                      所有的子节点。
     *                      然后在StandardContext去启动了StandardWrapper。
     *                      StandardWrapper load and start。
     *          6.4 Pipeline的启动。
     *          6.5 激发HostConfig监听器。
     *          (HostConfig ->t添加Host。) {@link HostConfig#start()}
     *          6.6 启动后台线程。
     *
     * Start this component and implement the requirements
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
     *
     * @exception LifecycleException if this component detects a fatal error
     *  that prevents this component from being used
     */
    @Override
    protected synchronized void startInternal() throws LifecycleException {

        // Start our subordinate components, if any
        logger = null;
        getLogger();
        //tomcat集群相关。
        Cluster cluster = getClusterInternal();
        if (cluster instanceof Lifecycle) {
            ((Lifecycle) cluster).start();
        }
        Realm realm = getRealmInternal();
        if (realm instanceof Lifecycle) {
            ((Lifecycle) realm).start();
        }

        // Start our child containers, if any
        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 = null;

        for (Future<Void> result : results) {
            try {
                result.get();
            } catch (Throwable e) {
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
                if (multiThrowable == null) {
                    multiThrowable = new MultiThrowable();
                }
                multiThrowable.add(e);
            }

        }
        if (multiThrowable != null) {
            throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                    multiThrowable.getThrowable());
        }

        // Start the Valves in our pipeline (including the basic), if any
        if (pipeline instanceof Lifecycle) {
            ((Lifecycle) pipeline).start();
        }


        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();
    }

在这里插入图片描述
在这里插入图片描述

后续流程也就是一个链路了,和上面的图类似。不做介绍了。感兴趣的玩家请自行下载源码去跟踪查看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值