zoukankan      html  css  js  c++  java
  • 简单读!tomcat源码(一)启动与监听

      tomcat 作为知名的web容器,很棒! 本文简单了从其应用命令开始拆解,让我们对他有清晰的了解,揭开神秘的面纱!(冗长的代码流水线,给你一目了然)

    话分两头:

               1. tomcat是如何启动的?

               2. tomcat是如何接收请求的?

               x. 应用程序是怎样接入tomcat的?

    从何处开始?

    /etc/init.d/tomcat8 start    # 简单的 tomcat8 脚本封装
    /usr/java/jdk1.8.0_101/bin/java org.apache.catalina.startup.Bootstrap "$@" start # 参考eval命令 eval ""$_RUNJAVA"" $JAVA_OPTS $CATALINA_OPTS -Djava.endorsed.dirs=""$JAVA_ENDORSED_DIRS"" -classpath ""$CLASSPATH"" -Dcatalina.base=""$CATALINA_BASE"" -Dcatalina.home=""$CATALINA_HOME"" -Djava.io.tmpdir=""$CATALINA_TMPDIR"" org.apache.catalina.startup.Bootstrap "$@" start "2>&1" | /usr/local/sbin/cronolog -S "$CATALINA_BASE"/logs/catalina_ln.out "$CATALINA_BASE"/logs/catalina.%Y-%m-%d-%H.out >> /dev/null & # 运行后得到结果 /usr/java/jdk1.8.0_101/bin/java -server -Xmx6144M -Xms1024M -Dfile.encoding=UTF-8 -Xloggc:/opt/tomcat7/logs/tomcat_app_gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/tomcat7/logs/ -classpath /opt/tomcat8/bin/bootstrap.jar:/opt/tomcat8/bin/tomcat-juli.jar -Dcatalina.base="/opt/tomcat8" -Dcatalina.home="/opt/tomcat8" org.apache.catalina.startup.Bootstrap "$@" start "2>&1"


    可以看到,tomcat最终是执行 org.apache.catalina.startup.Bootstrap 的 main() 方法,参数为 start ...

    那么,我们就以此为起点,进行简单查看下 tomcat 的一些运行原理吧!

      在进入main() 运行前,将会进行些home目录的检测,此方法在 Bootstrap 的静态方法块中:

        static {
            // Will always be non-null
            String userDir = System.getProperty("user.dir");
    
            // Home first
            String home = System.getProperty(Globals.CATALINA_HOME_PROP);
            File homeFile = null;
    
            if (home != null) {
                File f = new File(home);
                try {
                    homeFile = f.getCanonicalFile();
                } catch (IOException ioe) {
                    homeFile = f.getAbsoluteFile();
                }
            }
    
            if (homeFile == null) {
                // First fall-back. See if current directory is a bin directory
                // in a normal Tomcat install
                File bootstrapJar = new File(userDir, "bootstrap.jar");
    
                if (bootstrapJar.exists()) {
                    File f = new File(userDir, "..");
                    try {
                        homeFile = f.getCanonicalFile();
                    } catch (IOException ioe) {
                        homeFile = f.getAbsoluteFile();
                    }
                }
            }
    
            if (homeFile == null) {
                // Second fall-back. Use current directory
                File f = new File(userDir);
                try {
                    homeFile = f.getCanonicalFile();
                } catch (IOException ioe) {
                    homeFile = f.getAbsoluteFile();
                }
            }
    
            catalinaHomeFile = homeFile;
            System.setProperty(
                    Globals.CATALINA_HOME_PROP, catalinaHomeFile.getPath());
    
            // Then base
            String base = System.getProperty(Globals.CATALINA_BASE_PROP);
            if (base == null) {
                catalinaBaseFile = catalinaHomeFile;
            } else {
                File baseFile = new File(base);
                try {
                    baseFile = baseFile.getCanonicalFile();
                } catch (IOException ioe) {
                    baseFile = baseFile.getAbsoluteFile();
                }
                catalinaBaseFile = baseFile;
            }
            System.setProperty(
                    Globals.CATALINA_BASE_PROP, catalinaBaseFile.getPath());
        }
    View Code

    // org.apache.catalina.startup.Bootstrap main()入口,启动失败时,直接调用 System.exit(1); 退出jvm.

       public static void main(String args[]) {
            
            // 开始执行,先进行各种初始化操作,然后再解析命令,进行相应方法调用
            if (daemon == null) {
                // Don't set daemon until init() has completed
                Bootstrap bootstrap = new Bootstrap();
                try {
                    bootstrap.init();
                } catch (Throwable t) {
                    handleThrowable(t);
                    t.printStackTrace();
                    return;
                }
                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);
            }
    
            try {
                // 解析命令行,以最后一个参数作为启动或停止指令,默认为启动操作,但是外部的tomcat脚本可以防止不传入该参数
                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")) {
                    // 重点以start为例
                    daemon.setAwait(true);
                    daemon.load(args);
                    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);
            }
    
        }

    // 接下来我们先看看初始化过程: bootstrap.init(); 也就是自身的 init() 方法。

        /**
         * Initialize daemon.
         * @throws Exception Fatal initialization error
         */
        public void init() throws Exception {
    
            // 设置 classLoader, 因该classLoader是tomcat定义的,可由外部传入,所以不能直接加载类,如: WebappClassLoader, SharedClassLoader
            initClassLoaders();
    
            // 设置classLoader到当前线程,以备后续调用
            Thread.currentThread().setContextClassLoader(catalinaLoader);
    
            // 加载关键的各种系统类,使用自定义的classLoader
            SecurityClassLoad.securityClassLoad(catalinaLoader);
    
            // 由于加载默认应用时报错,找不到 JSP Compiler, 因此加上此句主动加载, 临时解决问题
            catalinaLoader.loadClass("org.apache.jasper.servlet.JasperInitializer");
            new JasperInitializer();
    
            // 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, 将 catalina 实例中放入 sharedClassLoader
            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;
            Method method =
                startupInstance.getClass().getMethod(methodName, paramTypes);
            method.invoke(startupInstance, paramValues);
    
            catalinaDaemon = startupInstance;
    
        }
    
        // step1. 加载 classLoader
        private void initClassLoaders() {
            try {
                // 创建 common
                commonLoader = createClassLoader("common", null);
                if( commonLoader == null ) {
                    // no config file, default to this loader - we might be in a 'single' env.
                    commonLoader=this.getClass().getClassLoader();
                }
                catalinaLoader = createClassLoader("server", commonLoader);
                sharedLoader = createClassLoader("shared", commonLoader);
            } catch (Throwable t) {
                handleThrowable(t);
                log.error("Class loader creation threw exception", t);
                System.exit(1);
            }
        }
        // 
        private ClassLoader createClassLoader(String name, ClassLoader parent)
            throws Exception {
    
            // "${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar"
            String value = CatalinaProperties.getProperty(name + ".loader");
            if ((value == null) || (value.equals("")))
                return parent;
    
            // 将 ${xx} 替换为具体的路径,转换为绝对路径 
            value = replace(value);
    
            List<Repository> repositories = new ArrayList<>();
    
            // 解析每个路径,然后依次加载
            String[] repositoryPaths = getPaths(value);
    
            for (String repository : repositoryPaths) {
                // Check for a JAR URL repository
                try {
                    @SuppressWarnings("unused")
                    URL url = new URL(repository);
                    repositories.add(
                            new Repository(repository, RepositoryType.URL));
                    continue;
                } catch (MalformedURLException e) {
                    // Ignore
                }
    
                // Local repository
                if (repository.endsWith("*.jar")) {
                    repository = repository.substring
                        (0, repository.length() - "*.jar".length());
                    repositories.add(
                            new Repository(repository, RepositoryType.GLOB));
                } else if (repository.endsWith(".jar")) {
                    repositories.add(
                            new Repository(repository, RepositoryType.JAR));
                } else {
                    repositories.add(
                            new Repository(repository, RepositoryType.DIR));
                }
            }
    
            // 将上面加载的目录文件,进行加载到内存
            return ClassLoaderFactory.createClassLoader(repositories, parent);
        }


    // org.apache.catalina.startup.ClassLoaderFactory 工厂类

        /**
         * Create and return a new class loader, based on the configuration
         * defaults and the specified directory paths:
         *
         * @param repositories List of class directories, jar files, jar directories
         *                     or URLS that should be added to the repositories of
         *                     the class loader.
         * @param parent Parent class loader for the new class loader, or
         *  <code>null</code> for the system class loader.
         * @return the new class loader
         *
         * @exception Exception if an error occurs constructing the class loader
         */
        public static ClassLoader createClassLoader(List<Repository> repositories,
                                                    final ClassLoader parent)
            throws Exception {
    
            if (log.isDebugEnabled())
                log.debug("Creating new class loader");
    
            // Construct the "class path" for this class loader
            Set<URL> set = new LinkedHashSet<>();
    
            if (repositories != null) {
                for (Repository repository : repositories)  {
                    if (repository.getType() == RepositoryType.URL) {
                        URL url = buildClassLoaderUrl(repository.getLocation());
                        if (log.isDebugEnabled())
                            log.debug("  Including URL " + url);
                        set.add(url);
                    } else if (repository.getType() == RepositoryType.DIR) {
                        File directory = new File(repository.getLocation());
                        directory = directory.getCanonicalFile();
                        if (!validateFile(directory, RepositoryType.DIR)) {
                            continue;
                        }
                        URL url = buildClassLoaderUrl(directory);
                        if (log.isDebugEnabled())
                            log.debug("  Including directory " + url);
                        set.add(url);
                    } else if (repository.getType() == RepositoryType.JAR) {
                        File file=new File(repository.getLocation());
                        file = file.getCanonicalFile();
                        if (!validateFile(file, RepositoryType.JAR)) {
                            continue;
                        }
                        URL url = buildClassLoaderUrl(file);
                        if (log.isDebugEnabled())
                            log.debug("  Including jar file " + url);
                        set.add(url);
                    } else if (repository.getType() == RepositoryType.GLOB) {
                        File directory=new File(repository.getLocation());
                        directory = directory.getCanonicalFile();
                        if (!validateFile(directory, RepositoryType.GLOB)) {
                            continue;
                        }
                        if (log.isDebugEnabled())
                            log.debug("  Including directory glob "
                                + directory.getAbsolutePath());
                        String filenames[] = directory.list();
                        if (filenames == null) {
                            continue;
                        }
                        for (int j = 0; j < filenames.length; j++) {
                            String filename = filenames[j].toLowerCase(Locale.ENGLISH);
                            if (!filename.endsWith(".jar"))
                                continue;
                            File file = new File(directory, filenames[j]);
                            file = file.getCanonicalFile();
                            if (!validateFile(file, RepositoryType.JAR)) {
                                continue;
                            }
                            if (log.isDebugEnabled())
                                log.debug("    Including glob jar file "
                                    + file.getAbsolutePath());
                            URL url = buildClassLoaderUrl(file);
                            set.add(url);
                        }
                    }
                }
            }
    
            // Construct the class loader itself
            final URL[] array = set.toArray(new URL[set.size()]);
            if (log.isDebugEnabled())
                for (int i = 0; i < array.length; i++) {
                    log.debug("  location " + i + " is " + array[i]);
                }
    
            return AccessController.doPrivileged(
                    new PrivilegedAction<URLClassLoader>() {
                        @Override
                        public URLClassLoader run() {
                            if (parent == null)
                                return new URLClassLoader(array);
                            else
                                return new URLClassLoader(array, parent);
                        }
                    });
        }


    // org.apache.catalina.security.SecurityClassLoad 加载系统关键类

    public final class SecurityClassLoad {
    
        public static void securityClassLoad(ClassLoader loader) throws Exception {
            securityClassLoad(loader, true);
        }
    
        static void securityClassLoad(ClassLoader loader, boolean requireSecurityManager) throws Exception {
    
            if (requireSecurityManager && System.getSecurityManager() == null) {
                return;
            }
    
            // 清晰地加载各种系统类库
            loadCorePackage(loader);
            loadCoyotePackage(loader);
            loadLoaderPackage(loader);
            loadRealmPackage(loader);
            loadServletsPackage(loader);
            loadSessionPackage(loader);
            loadUtilPackage(loader);
            loadValvesPackage(loader);
            loadJavaxPackage(loader);
            loadConnectorPackage(loader);
            loadTomcatPackage(loader);
        }
    
        private static final void loadCorePackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.core.";
            loader.loadClass(basePackage + "AccessLogAdapter");
            loader.loadClass(basePackage + "ApplicationContextFacade$PrivilegedExecuteMethod");
            loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedForward");
            loader.loadClass(basePackage + "ApplicationDispatcher$PrivilegedInclude");
            loader.loadClass(basePackage + "ApplicationPushBuilder");
            loader.loadClass(basePackage + "AsyncContextImpl");
            loader.loadClass(basePackage + "AsyncContextImpl$AsyncRunnable");
            loader.loadClass(basePackage + "AsyncContextImpl$DebugException");
            loader.loadClass(basePackage + "AsyncListenerWrapper");
            loader.loadClass(basePackage + "ContainerBase$PrivilegedAddChild");
            loadAnonymousInnerClasses(loader, basePackage + "DefaultInstanceManager");
            loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntry");
            loader.loadClass(basePackage + "DefaultInstanceManager$AnnotationCacheEntryType");
            loader.loadClass(basePackage + "ApplicationHttpRequest$AttributeNamesEnumerator");
        }
    
        private static final void loadLoaderPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.loader.";
            loader.loadClass(basePackage + "WebappClassLoaderBase$PrivilegedFindClassByName");
            loader.loadClass(basePackage + "WebappClassLoaderBase$PrivilegedHasLoggingConfig");
        }
    
        private static final void loadRealmPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.realm.";
            loader.loadClass(basePackage + "LockOutRealm$LockRecord");
        }
    
        private static final void loadServletsPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.servlets.";
            // Avoid a possible memory leak in the DefaultServlet when running with
            // a security manager. The DefaultServlet needs to load an XML parser
            // when running under a security manager. We want this to be loaded by
            // the container rather than a web application to prevent a memory leak
            // via web application class loader.
            loader.loadClass(basePackage + "DefaultServlet");
        }
    
        private static final void loadSessionPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.session.";
            loader.loadClass(basePackage + "StandardSession");
            loadAnonymousInnerClasses(loader, basePackage + "StandardSession");
            loader.loadClass(basePackage + "StandardManager$PrivilegedDoUnload");
        }
    
        private static final void loadUtilPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.util.";
            loader.loadClass(basePackage + "ParameterMap");
            loader.loadClass(basePackage + "RequestUtil");
            loader.loadClass(basePackage + "TLSUtil");
        }
    
        private static final void loadValvesPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.valves.";
            loadAnonymousInnerClasses(loader, basePackage + "AbstractAccessLogValve");
        }
    
        private static final void loadCoyotePackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.coyote.";
            loader.loadClass(basePackage + "http11.Constants");
            // Make sure system property is read at this point
            Class<?> clazz = loader.loadClass(basePackage + "Constants");
            clazz.getConstructor().newInstance();
            loader.loadClass(basePackage + "http2.Stream$PrivilegedPush");
        }
    
        private static final void loadJavaxPackage(ClassLoader loader) throws Exception {
            loader.loadClass("javax.servlet.http.Cookie");
        }
    
        private static final void loadConnectorPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.catalina.connector.";
            loader.loadClass(basePackage + "RequestFacade$GetAttributePrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetParameterMapPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetRequestDispatcherPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetParameterPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetParameterNamesPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetParameterValuePrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetCharacterEncodingPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetHeadersPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetHeaderNamesPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetCookiesPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetLocalePrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetLocalesPrivilegedAction");
            loader.loadClass(basePackage + "ResponseFacade$SetContentTypePrivilegedAction");
            loader.loadClass(basePackage + "ResponseFacade$DateHeaderPrivilegedAction");
            loader.loadClass(basePackage + "RequestFacade$GetSessionPrivilegedAction");
            loadAnonymousInnerClasses(loader, basePackage + "ResponseFacade");
            loadAnonymousInnerClasses(loader, basePackage + "OutputBuffer");
            loadAnonymousInnerClasses(loader, basePackage + "CoyoteInputStream");
            loadAnonymousInnerClasses(loader, basePackage + "InputBuffer");
            loadAnonymousInnerClasses(loader, basePackage + "Response");
        }
    
        private static final void loadTomcatPackage(ClassLoader loader) throws Exception {
            final String basePackage = "org.apache.tomcat.";
            // buf
            loader.loadClass(basePackage + "util.buf.B2CConverter");
            loader.loadClass(basePackage + "util.buf.ByteBufferUtils");
            loader.loadClass(basePackage + "util.buf.C2BConverter");
            loader.loadClass(basePackage + "util.buf.HexUtils");
            loader.loadClass(basePackage + "util.buf.StringCache");
            loader.loadClass(basePackage + "util.buf.StringCache$ByteEntry");
            loader.loadClass(basePackage + "util.buf.StringCache$CharEntry");
            loader.loadClass(basePackage + "util.buf.UriUtil");
            // collections
            Class<?> clazz = loader.loadClass(basePackage + "util.collections.CaseInsensitiveKeyMap");
            // Ensure StringManager is configured
            clazz.getConstructor().newInstance();
            loader.loadClass(basePackage + "util.collections.CaseInsensitiveKeyMap$EntryImpl");
            loader.loadClass(basePackage + "util.collections.CaseInsensitiveKeyMap$EntryIterator");
            loader.loadClass(basePackage + "util.collections.CaseInsensitiveKeyMap$EntrySet");
            loader.loadClass(basePackage + "util.collections.CaseInsensitiveKeyMap$Key");
            // http
            loader.loadClass(basePackage + "util.http.CookieProcessor");
            loader.loadClass(basePackage + "util.http.NamesEnumerator");
            // Make sure system property is read at this point
            clazz = loader.loadClass(basePackage + "util.http.FastHttpDateFormat");
            clazz.getConstructor().newInstance();
            loader.loadClass(basePackage + "util.http.parser.HttpParser");
            loader.loadClass(basePackage + "util.http.parser.MediaType");
            loader.loadClass(basePackage + "util.http.parser.MediaTypeCache");
            loader.loadClass(basePackage + "util.http.parser.SkipResult");
            // net
            loader.loadClass(basePackage + "util.net.Constants");
            loader.loadClass(basePackage + "util.net.DispatchType");
            loader.loadClass(basePackage + "util.net.NioBlockingSelector$BlockPoller$RunnableAdd");
            loader.loadClass(basePackage + "util.net.NioBlockingSelector$BlockPoller$RunnableCancel");
            loader.loadClass(basePackage + "util.net.NioBlockingSelector$BlockPoller$RunnableRemove");
            // security
            loader.loadClass(basePackage + "util.security.PrivilegedGetTccl");
            loader.loadClass(basePackage + "util.security.PrivilegedSetTccl");
        }
    
        private static final void loadAnonymousInnerClasses(ClassLoader loader, String enclosingClass) {
            try {
                for (int i = 1;; i++) {
                    loader.loadClass(enclosingClass + '$' + i);
                }
            } catch (ClassNotFoundException ignored) {
                //
            }
        }
    }

     // 初始化完成后,准备启动tomcat了

            // 启动时序
            if (command.equals("start")) {
                // 设置标志位
                daemon.setAwait(true);
                // 加载参数
                daemon.load(args);
                // 启动监听
                daemon.start();
                if (null == daemon.getServer()) {
                    System.exit(1);
                }
            }
            
        /**
         * Set flag.
         * @param await <code>true</code> if the daemon should block
         * @throws Exception Reflection error
         */
        public void setAwait(boolean await)
            throws Exception {
    
            Class<?> paramTypes[] = new Class[1];
            paramTypes[0] = Boolean.TYPE;
            Object paramValues[] = new Object[1];
            paramValues[0] = Boolean.valueOf(await);
            Method method =
                catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
            method.invoke(catalinaDaemon, paramValues); // 一个简单的方法,尽也用反射操作,奇怪不?
    
        }
        
        
        // 加载参数配置,设置
        /**
         * Load daemon.
         */
        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;
            }
            Method method =
                catalinaDaemon.getClass().getMethod(methodName, paramTypes);
            if (log.isDebugEnabled())
                log.debug("Calling startup class " + method);
            method.invoke(catalinaDaemon, param);  // 反射调用 Catalina.load() 方法
    
        }

    // 调用 org.apache.catalina.startup.Catalina.load()

        /**
         * Start a new server instance.
         */
        public void load() {
    
            // 只加载一次
            if (loaded) {
                return;
            }
            loaded = true;
    
            long t1 = System.nanoTime();
    
            // 检查临时目录设置
            initDirs();
    
            // Before digester - it may be needed
            initNaming();
    
            // Create and execute our Digester
            // 初始化 server.xml 的配置项
            Digester digester = createStartDigester();
    
            InputSource inputSource = null;
            InputStream inputStream = null;
            File file = null;
            try {
                try {
                    // 加载配置 server.xml
                    file = configFile();
                    inputStream = new FileInputStream(file);
                    inputSource = new InputSource(file.toURI().toURL().toString());
                } catch (Exception e) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("catalina.configFail", file), e);
                    }
                }
                if (inputStream == null) {
                    try {
                        inputStream = getClass().getClassLoader()
                            .getResourceAsStream(getConfigFile());
                        inputSource = new InputSource
                            (getClass().getClassLoader()
                             .getResource(getConfigFile()).toString());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("catalina.configFail",
                                    getConfigFile()), e);
                        }
                    }
                }
    
                // This should be included in catalina.jar
                // Alternative: don't bother with xml, just create it manually.
                if (inputStream == null) {
                    try {
                        inputStream = getClass().getClassLoader()
                                .getResourceAsStream("server-embed.xml");
                        inputSource = new InputSource
                        (getClass().getClassLoader()
                                .getResource("server-embed.xml").toString());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("catalina.configFail",
                                    "server-embed.xml"), e);
                        }
                    }
                }
    
    
                if (inputStream == null || inputSource == null) {
                    if  (file == null) {
                        log.warn(sm.getString("catalina.configFail",
                                getConfigFile() + "] or [server-embed.xml]"));
                    } else {
                        log.warn(sm.getString("catalina.configFail",
                                file.getAbsolutePath()));
                        if (file.exists() && !file.canRead()) {
                            log.warn("Permissions incorrect, read permission is not allowed on the file.");
                        }
                    }
                    return;
                }
    
                try {
                    inputSource.setByteStream(inputStream);
                    // Catalina 加入栈,解析server.xml, server 在此时创建
                    digester.push(this);
                    digester.parse(inputSource);
                } catch (SAXParseException spe) {
                    log.warn("Catalina.start using " + getConfigFile() + ": " +
                            spe.getMessage());
                    return;
                } catch (Exception e) {
                    log.warn("Catalina.start using " + getConfigFile() + ": " , e);
                    return;
                }
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            }
    
            getServer().setCatalina(this);
            getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
            getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    
            // Stream redirection
            initStreams();
    
            // Start the new server
            try {
                getServer().init();  // 关键: 初始化server, 会进入到 StandardServer 的 lifeCycle 中
            } catch (LifecycleException e) {
                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                    throw new java.lang.Error(e);
                } else {
                    log.error("Catalina.start", e);
                }
            }
    
            long t2 = System.nanoTime();
            if(log.isInfoEnabled()) {
                log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
            }
        }
    
        /**
         * Create and configure the Digester we will be using for startup.
         * @return the main digester to parse server.xml
         */
        protected Digester createStartDigester() {
            long t1=System.currentTimeMillis();
            // Initialize the digester
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setRulesValidation(true);
            HashMap<Class<?>, List<String>> fakeAttributes = new HashMap<>();
            ArrayList<String> attrs = new ArrayList<>();
            attrs.add("className");
            fakeAttributes.put(Object.class, attrs);
            digester.setFakeAttributes(fakeAttributes);
            digester.setUseContextClassLoader(true);
    
            // Configure the actions we will be using
            digester.addObjectCreate("Server",
                                     "org.apache.catalina.core.StandardServer",
                                     "className");
            digester.addSetProperties("Server");
            digester.addSetNext("Server",
                                "setServer",
                                "org.apache.catalina.Server");
    
            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);
    
        }
        
        
        protected File configFile() {
    
            File file = new File(configFile);
            if (!file.isAbsolute()) {
                file = new File(Bootstrap.getCatalinaBase(), configFile);
            }
            return (file);
    
        }

    ObjectCreate 如下:

        /**
         * Add an "object create" rule for the specified parameters.
         *
         * @param pattern Element matching pattern
         * @param className Default Java class name to be created
         * @param attributeName Attribute name that optionally overrides
         *  the default Java class name to be created
         * @see ObjectCreateRule
         */
        public void addObjectCreate(String pattern, String className, String attributeName) {
    
            addRule(pattern, new ObjectCreateRule(className, attributeName));
        }


    // org.apache.tomcat.util.digester.Digester.push() 入栈, parse() 解析配置文件

        /**
         * Push a new object onto the top of the object stack.
         *
         * @param object The new object
         */
        public void push(Object object) {
    
            if (stack.size() == 0) {
                root = object;
            }
            stack.push(object);
    
        }
        
        /**
         * Parse the content of the specified input source using this Digester.
         * Returns the root element from the object stack (if any).
         *
         * @param input Input source containing the XML data to be parsed
         * @return the root object
         * @exception IOException if an input/output error occurs
         * @exception SAXException if a parsing exception occurs
         */
        public Object parse(InputSource input) throws IOException, SAXException {
    
            configure();
            getXMLReader().parse(input);
            return (root);
    
        }
    View Code

    插播,我们顺便看看获取 MBean的过程,使用读写锁进行操作,提升效率! org.apache.tomcat.util.modeler.ManagedBean.getMBeanInfo()

        /**
         * Create and return a <code>ModelMBeanInfo</code> object that
         * describes this entire managed bean.
         * @return the MBean info
         */
        MBeanInfo getMBeanInfo() {
    
            // Return our cached information (if any)
            mBeanInfoLock.readLock().lock();
            try {
                if (info != null) {
                    return info;
                }
            } finally {
                mBeanInfoLock.readLock().unlock();
            }
    
            mBeanInfoLock.writeLock().lock();
            try {
                if (info == null) {
                    // Create subordinate information descriptors as required
                    AttributeInfo attrs[] = getAttributes();
                    MBeanAttributeInfo attributes[] =
                        new MBeanAttributeInfo[attrs.length];
                    for (int i = 0; i < attrs.length; i++)
                        attributes[i] = attrs[i].createAttributeInfo();
    
                    OperationInfo opers[] = getOperations();
                    MBeanOperationInfo operations[] =
                        new MBeanOperationInfo[opers.length];
                    for (int i = 0; i < opers.length; i++)
                        operations[i] = opers[i].createOperationInfo();
    
    
                    NotificationInfo notifs[] = getNotifications();
                    MBeanNotificationInfo notifications[] =
                        new MBeanNotificationInfo[notifs.length];
                    for (int i = 0; i < notifs.length; i++)
                        notifications[i] = notifs[i].createNotificationInfo();
    
    
                    // Construct and return a new ModelMBeanInfo object
                    info = new MBeanInfo(getClassName(),
                                         getDescription(),
                                         attributes,
                                         new MBeanConstructorInfo[] {},
                                         operations,
                                         notifications);
                }
    
                return info;
            } finally {
                mBeanInfoLock.writeLock().unlock();
            }
        }
        
        // 获取 MBeanServer()时,直接调用 util/modeler/Registry , 然后 从 MBeanServerFactory 获取
        /**
         * Factory method to create (if necessary) and return our
         * <code>MBeanServer</code> instance.
         * @return the MBean server
         */
        public synchronized MBeanServer getMBeanServer() {
            if (server == null) {
                long t1 = System.currentTimeMillis();
                // 先查找是否已配置了 MBeanServer
                if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
                    server = MBeanServerFactory.findMBeanServer(null).get(0);
                    if (log.isDebugEnabled()) {
                        log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1));
                    }
                } else {
                    // 如果没有配置, 则直接取 jdk 的 MBeanServer, JmxMBeanServer
                    server = ManagementFactory.getPlatformMBeanServer();
                    if (log.isDebugEnabled()) {
                        log.debug("Creating MBeanServer" + (System.currentTimeMillis() - t1));
                    }
                }
            }
            return server;
        }
        
        /**
         * <p>Return a list of registered MBeanServer objects.  A
         * registered MBeanServer object is one that was created by one of
         * the <code>createMBeanServer</code> methods and not subsequently
         * released with <code>releaseMBeanServer</code>.</p>
         *
         * @param agentId The agent identifier of the MBeanServer to
         * retrieve.  If this parameter is null, all registered
         * MBeanServers in this JVM are returned.  Otherwise, only
         * MBeanServers whose id is equal to <code>agentId</code> are
         * returned.  The id of an MBeanServer is the
         * <code>MBeanServerId</code> attribute of its delegate MBean.
         *
         * @return A list of MBeanServer objects.
         *
         * @exception SecurityException if there is a SecurityManager and the
         * caller's permissions do not include or imply <code>{@link
         * MBeanServerPermission}("findMBeanServer")</code>.
         */
        public synchronized static
                ArrayList<MBeanServer> findMBeanServer(String agentId) {
    
            checkPermission("findMBeanServer");
    
            if (agentId == null)
                return new ArrayList<MBeanServer>(mBeanServerList);
    
            ArrayList<MBeanServer> result = new ArrayList<MBeanServer>();
            for (MBeanServer mbs : mBeanServerList) {
                String name = mBeanServerId(mbs);
                if (agentId.equals(name))
                    result.add(mbs);
            }
            return result;
        }
    
        // org.apache.catalina.mbeans.MBeanUtils 在初始化的时候就会创建几个单例应用
        /**
         * The configuration information registry for our managed beans.
         */
        private static Registry registry = createRegistry();
    
    
        /**
         * The <code>MBeanServer</code> for this application.
         */
        private static MBeanServer mserver = createServer();
    
    
        /**
         * Create and configure (if necessary) and return the registry of
         * managed object descriptions.
         * @return the singleton registry
         */
        public static synchronized Registry createRegistry() {
    
            if (registry == null) {
                registry = Registry.getRegistry(null, null);
                ClassLoader cl = MBeanUtils.class.getClassLoader();
    
                registry.loadDescriptors("org.apache.catalina.mbeans",  cl);
                registry.loadDescriptors("org.apache.catalina.authenticator", cl);
                registry.loadDescriptors("org.apache.catalina.core", cl);
                registry.loadDescriptors("org.apache.catalina", cl);
                registry.loadDescriptors("org.apache.catalina.deploy", cl);
                registry.loadDescriptors("org.apache.catalina.loader", cl);
                registry.loadDescriptors("org.apache.catalina.realm", cl);
                registry.loadDescriptors("org.apache.catalina.session", cl);
                registry.loadDescriptors("org.apache.catalina.startup", cl);
                registry.loadDescriptors("org.apache.catalina.users", cl);
                registry.loadDescriptors("org.apache.catalina.ha", cl);
                registry.loadDescriptors("org.apache.catalina.connector", cl);
                registry.loadDescriptors("org.apache.catalina.valves",  cl);
                registry.loadDescriptors("org.apache.catalina.storeconfig",  cl);
                registry.loadDescriptors("org.apache.tomcat.util.descriptor.web",  cl);
            }
            return (registry);
    
        }
    View Code

    // org.apache.catalina.util.LifeCycleBase.init(), 很多实现都继承该该,进行生命周期的管理!

        @Override
        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);
            }
        }
    
        // setStateInternal, 设置当前运行状态
        private synchronized void setStateInternal(LifecycleState state,
                Object data, boolean check) throws LifecycleException {
    
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("lifecycleBase.setState", this, state));
            }
    
            if (check) {
                // Must have been triggered by one of the abstract methods (assume
                // code in this class is correct)
                // null is never a valid state
                if (state == null) {
                    invalidTransition("null");
                    // Unreachable code - here to stop eclipse complaining about
                    // a possible NPE further down the method
                    return;
                }
    
                // Any method can transition to failed
                // startInternal() permits STARTING_PREP to STARTING
                // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
                // STOPPING
                if (!(state == LifecycleState.FAILED ||
                        (this.state == LifecycleState.STARTING_PREP &&
                                state == LifecycleState.STARTING) ||
                        (this.state == LifecycleState.STOPPING_PREP &&
                                state == LifecycleState.STOPPING) ||
                        (this.state == LifecycleState.FAILED &&
                                state == LifecycleState.STOPPING))) {
                    // No other transition permitted
                    invalidTransition(state.name());
                }
            }
    
            this.state = state;
            String lifecycleEvent = state.getLifecycleEvent();
            if (lifecycleEvent != null) {
                fireLifecycleEvent(lifecycleEvent, data);
            }
        }

     org.apache.catalina.deploy.NamingResourcesImpl: 负责对一些必须资源的管理!

        // 进行事件监听通知
        /**
         * Allow sub classes to fire {@link Lifecycle} events.
         *
         * @param type  Event type
         * @param data  Data associated with event.
         */
        protected void fireLifecycleEvent(String type, Object data) {
            LifecycleEvent event = new LifecycleEvent(this, type, data);
            // NamingContextListener
            // VersionLoggerListener
            // AprLifecycleListener
            // JreMemoryLeakPreventionListener
            // GlobalResourcesLifecycleListener
            // ThreadLocalLeakPreventionListener
            for (LifecycleListener listener : lifecycleListeners) {
                listener.lifecycleEvent(event);
            }
        }
    
        // org.apache.catalina.core.StandardServer.initInternal()
        /**
         * Invoke a pre-startup initialization. This is used to allow connectors
         * to bind to restricted ports under Unix operating environments.
         */
        @Override
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // Register global String cache
            // Note although the cache is global, if there are multiple Servers
            // present in the JVM (may happen when embedding) then the same cache
            // will be registered under multiple names
            onameStringCache = register(new StringCache(), "type=StringCache");
    
            // Register the MBeanFactory
            MBeanFactory factory = new MBeanFactory();
            factory.setContainer(this);
            onameMBeanFactory = register(factory, "type=MBeanFactory");
    
            // Register the naming resources
            globalNamingResources.init();
    
            // Populate the extension validator with JARs from common and shared
            // class loaders
            if (getCatalina() != null) {
                ClassLoader cl = getCatalina().getParentClassLoader();
                // Walk the class loader hierarchy. Stop at the system class loader.
                // This will add the shared (if present) and common class loaders
                while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
                    if (cl instanceof URLClassLoader) {
                        URL[] urls = ((URLClassLoader) cl).getURLs();
                        for (URL url : urls) {
                            if (url.getProtocol().equals("file")) {
                                try {
                                    File f = new File (url.toURI());
                                    if (f.isFile() &&
                                            f.getName().endsWith(".jar")) {
                                        ExtensionValidator.addSystemResource(f);
                                    }
                                } catch (URISyntaxException e) {
                                    // Ignore
                                } catch (IOException e) {
                                    // Ignore
                                }
                            }
                        }
                    }
                    cl = cl.getParent();
                }
            }
            // Initialize our defined Services
            for (int i = 0; i < services.length; i++) {
                services[i].init();
            }
        }
        
        // org.apache.catalina.util.LifecycleMBeanBase.initInternal()
        /**
         * Sub-classes wishing to perform additional initialization should override
         * this method, ensuring that super.initInternal() is the first call in the
         * overriding method.
         */
        @Override
        protected void initInternal() throws LifecycleException {
    
            // If oname is not null then registration has already happened via
            // preRegister().
            if (oname == null) {
                mserver = Registry.getRegistry(null, null).getMBeanServer();
    
                oname = register(this, getObjectNameKeyProperties());
            }
        }
        
        /**
         * Utility method to enable sub-classes to easily register additional
         * components that don't implement {@link JmxEnabled} with an MBean server.
         * <br>
         * Note: This method should only be used once {@link #initInternal()} has
         * been called and before {@link #destroyInternal()} has been called.
         *
         * @param obj                       The object the register
         * @param objectNameKeyProperties   The key properties component of the
         *                                  object name to use to register the
         *                                  object
         *
         * @return  The name used to register the object
         */
        protected final ObjectName register(Object obj,
                String objectNameKeyProperties) {
    
            // Construct an object name with the right domain
            StringBuilder name = new StringBuilder(getDomain());
            name.append(':');
            name.append(objectNameKeyProperties);
    
            ObjectName on = null;
    
            try {
                on = new ObjectName(name.toString());
    
                Registry.getRegistry(null, null).registerComponent(obj, on, null);
            } catch (MalformedObjectNameException e) {
                log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
                        e);
            } catch (Exception e) {
                log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
                        e);
            }
    
            return on;
        }
        
    View Code

    StandardServer.initInternal(), 负责server的逻辑处理:

        /**
         * Invoke a pre-startup initialization. This is used to allow connectors
         * to bind to restricted ports under Unix operating environments.
         */
        @Override
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // Register global String cache
            // Note although the cache is global, if there are multiple Servers
            // present in the JVM (may happen when embedding) then the same cache
            // will be registered under multiple names
            onameStringCache = register(new StringCache(), "type=StringCache");
    
            // Register the MBeanFactory
            MBeanFactory factory = new MBeanFactory();
            factory.setContainer(this);
            onameMBeanFactory = register(factory, "type=MBeanFactory");
    
            // Register the naming resources
            globalNamingResources.init();
    
            // Populate the extension validator with JARs from common and shared
            // class loaders
            if (getCatalina() != null) {
                ClassLoader cl = getCatalina().getParentClassLoader();
                // Walk the class loader hierarchy. Stop at the system class loader.
                // This will add the shared (if present) and common class loaders
                while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
                    if (cl instanceof URLClassLoader) {
                        URL[] urls = ((URLClassLoader) cl).getURLs();
                        for (URL url : urls) {
                            if (url.getProtocol().equals("file")) {
                                try {
                                    File f = new File (url.toURI());
                                    if (f.isFile() &&
                                            f.getName().endsWith(".jar")) {
                                        ExtensionValidator.addSystemResource(f);
                                    }
                                } catch (URISyntaxException e) {
                                    // Ignore
                                } catch (IOException e) {
                                    // Ignore
                                }
                            }
                        }
                    }
                    cl = cl.getParent();
                }
            }
            // Initialize our defined Services, 最后,调用 StandardService.init() 监听方法
            for (int i = 0; i < services.length; i++) {
                services[i].init();
            }
        }

     而 StandardService.init() 又会带动 initInternal 处理具体逻辑!

    // StandardService.initInternal() 初始化服务,Engin(),线程池。。。

        /**
         * Invoke a pre-startup initialization. This is used to allow connectors
         * to bind to restricted ports under Unix operating environments.
         */
        @Override
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // engin init, StandardEngine.init()
            if (engine != null) {
                engine.init();
            }
    
            // Initialize any Executors
            for (Executor executor : findExecutors()) {
                if (executor instanceof JmxEnabled) {
                    ((JmxEnabled) executor).setDomain(getDomain());
                }
                executor.init();
            }
    
            // Initialize mapper listener
            mapperListener.init();
    
            // Initialize our defined Connectors
            // 初始化连接器,如: Connector[HTTP/1.1-8080], Connector[AJP/1.3-8011]
            synchronized (connectorsLock) {
                for (Connector connector : connectors) {
                    try {
                        connector.init();
                    } catch (Exception e) {
                        String message = sm.getString(
                                "standardService.connector.initFailed", connector);
                        log.error(message, e);
    
                        if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                            throw new LifecycleException(message);
                    }
                }
            }
        }

    // org.apache.catalina.core.StandardEngine.initInternal(): 主要是检查 Realm 的设置,以及生成启动线程: Catalina-startStop-xx, 默认是1个线程启动;

        @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();
            super.initInternal();
        }
        
        
        // org.apache.catalina.core.ContainerBase.initInternal()
        // Catalina-startStop-xx 线程池创建
        @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();
        }
    
        
    
    // org.apache.catalina.connector.Connector
        @Override
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // Initialize adapter
            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 {
                protocolHandler.init();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
            }
        }
        
        // org.apache.coyote.AbstractProtocol.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);
    
            endpoint.init();
        }
        
        // org.apache.tomcat.util.net.AbstractEndpoint.init()
        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);
    
                for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                    registerJmx(sslHostConfig);
                }
            }
        }
    View Code

    接下来是对监听器的初始化工作: mapperListener.init(); 但是它没有什么特别的需要初始化的,所以直接交给父类操作了,而其自身的作用,则是启动过程发挥的!

    再往下,就是对 Connector 的初始化了,这也就是我们的应用服务了!其中最重要的,是开启了socket 监听!

        // org.apache.catalina.connector.Connector, 初始化 Connector 
        // 其主要实现依赖于 CoyoteAdapter
        @Override
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // Initialize adapter, httpProtocolHandler 是 Http11NioProtocol
            adapter = new CoyoteAdapter(this);
            protocolHandler.setAdapter(adapter);
    
            // Make sure parseBodyMethodsSet has a default
            // 设置默认的body的解析方法, 默认为 POST
            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 {
                // 根据协议调用相应初始化
                protocolHandler.init();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
            }
        }
        
        // org.apache.coyote.http11.AbstractHttp11Protocol
        // org.apache.coyote.http11.AbstractHttp11Protocol
        @Override
        public void init() throws Exception {
            for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
                configureUpgradeProtocol(upgradeProtocol);
            }
    
            super.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);
            }
    
            // 如 http-nio-8080, 由子类返回名称+端口号
            String endpointName = getName();
            endpoint.setName(endpointName.substring(1, endpointName.length()-1));
            endpoint.setDomain(domain);
    
            // Endpoint 为 NioEndpoint
            endpoint.init();
        }
        
        /**
         * The name will be prefix-address-port if address is non-null and
         * prefix-port if the address is null.
         *
         * @return A name for this protocol instance that is appropriately quoted
         *         for use in an ObjectName.
         */
        public String getName() {
            return ObjectName.quote(getNameInternal());
        }
        private String getNameInternal() {
            StringBuilder name = new StringBuilder(getNamePrefix());
            name.append('-');
            if (getAddress() != null) {
                name.append(getAddress().getHostAddress());
                name.append('-');
            }
            int port = getPort();
            if (port == 0) {
                // Auto binding is in use. Check if port is known
                name.append("auto-");
                name.append(getNameIndex());
                port = getLocalPort();
                if (port != -1) {
                    name.append('-');
                    name.append(port);
                }
            } else {
                name.append(port);
            }
            return name.toString();
        }
    
        // coyote.http11.Http11NioProtocol.getNamePrefix()
        @Override
        protected String getNamePrefix() {
            if (isSSLEnabled()) {
                return ("https-" + getSslImplementationShortName()+ "-nio");
            } else {
                return ("http-nio");
            }
        }
    
        // endpoint.init()
        // org.apache.tomcat.util.net.AbstractJsseEndpoint.init(), 添加证书验证逻辑
        @Override
        public void init() throws Exception {
            testServerCipherSuitesOrderSupport();
            // 调用父类初始化方法, 绑定服务端口
            super.init();
        }
        // org.apache.tomcat.util.net.AbstractEndpoint.init()
        public void init() throws Exception {
            if (bindOnInit) {
                // 直接调用子类 NioEndpoint.bind(), 打开服务端口
                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);
    
                for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                    registerJmx(sslHostConfig);
                }
            }
        }

     Connector 初始过程,会 调用如下 NioEndpoint.bind(), 打开socket连接

        /**
         * Initialize the endpoint.
         */
        @Override
        public void bind() throws Exception {
    
            if (!getUseInheritedChannel()) {
                serverSock = ServerSocketChannel.open();    // 来自jdk的nio socket 开启方式
                socketProperties.setProperties(serverSock.socket());  // 设置各项配置属性 // 然后再绑定host 和 端口号
                InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
                serverSock.socket().bind(addr,getAcceptCount());  // 默认的连接数是 100, 可以自行配置
            } else {
                // Retrieve the channel provided by the OS
                Channel ic = System.inheritedChannel();
                if (ic instanceof ServerSocketChannel) {
                    serverSock = (ServerSocketChannel) ic;
                }
                if (serverSock == null) {
                    throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
                }
            }
            serverSock.configureBlocking(true); //mimic APR behavior
    
            // Initialize thread count defaults for acceptor, poller, 默认的 acceptor 线程数为1, 即只会有一个线程监听前端请求
            if (acceptorThreadCount == 0) {
                // FIXME: Doesn't seem to work that well with multiple accept threads
                acceptorThreadCount = 1;
            }
            if (pollerThreadCount <= 0) {
                //minimum one poller thread, 默认 poller 线程数是 2, Math.min(2,Runtime.getRuntime().availableProcessors());
                pollerThreadCount = 1;
            }
            // 闭锁控制
            setStopLatch(new CountDownLatch(pollerThreadCount));
    
            // Initialize SSL if needed
            initialiseSsl();
    
            // 调用selector池,打开 select 连接
            selectorPool.open();
        }
        
        // org.apache.tomcat.util.net.NioSelectorPool.open()
        public void open() throws IOException {
            enabled = true;
            getSharedSelector();  // NioSelector, 调用 Selector.open() 开启平台相关的 jdk Selector
            if (SHARED) {      // 接下来还开启多个selector的阻塞等待
                blockingSelector = new NioBlockingSelector();
                blockingSelector.open(getSharedSelector());
            }
    
        }

       NioBlockingSelector.open();

        // NioBlockingSelector.open()
        public void open(Selector selector) {
            sharedSelector = selector;
            // 使用 BlockPoller 来处理实际业务, BlockPoller 是个内部类,可以共享该类的各种配置
            // 使用 SynchronizedQueue 来保存处理队列, 保证线程安全
            // BlockPoller 的主要作用是: 查询是否有需要进行处理的事件,如果有,则启动相应处理,否则阻塞等待
            poller = new BlockPoller();
            poller.selector = sharedSelector;
            poller.setDaemon(true);
            poller.setName("NioBlockingSelector.BlockPoller-"+(++threadCounter));
            // 初始化完成后,直接启动线程
            poller.start();
        }
        
            // BlockPoller 的 任务逻辑如下:
            @Override
            public void run() {
                while (run) {
                    try {
                        // 如果有需要处理的事件,则直接 调用 run 事件的 event.run() 运行任务;
                        // 所以,此处的任务其实是同步执行的
                        events();
                        int keyCount = 0;
                        try {
                            int i = wakeupCounter.get();
                            if (i>0)
                                keyCount = selector.selectNow();
                            else {
                                wakeupCounter.set(-1);
                                // 阻塞等待超时
                                keyCount = selector.select(1000);
                            }
                            wakeupCounter.set(0);
                            if (!run) break;
                        }catch ( NullPointerException x ) {
                            //sun bug 5076772 on windows JDK 1.5
                            if (selector==null) throw x;
                            if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
                            continue;
                        } catch ( CancelledKeyException x ) {
                            //sun bug 5076772 on windows JDK 1.5
                            if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
                            continue;
                        } catch (Throwable x) {
                            ExceptionUtils.handleThrowable(x);
                            log.error("",x);
                            continue;
                        }
    
                        Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;
    
                        // Walk through the collection of ready keys and dispatch
                        // any active event.
                        while (run && iterator != null && iterator.hasNext()) {
                            SelectionKey sk = iterator.next();
                            NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
                            try {
                                iterator.remove();
                                sk.interestOps(sk.interestOps() & (~sk.readyOps()));
                                if ( sk.isReadable() ) {
                                    countDown(attachment.getReadLatch());
                                }
                                if (sk.isWritable()) {
                                    countDown(attachment.getWriteLatch());
                                }
                            }catch (CancelledKeyException ckx) {
                                sk.cancel();
                                countDown(attachment.getReadLatch());
                                countDown(attachment.getWriteLatch());
                            }
                        }//while
                    }catch ( Throwable t ) {
                        log.error("",t);
                    }
                }
                // 异常处理
                events.clear();
                // If using a shared selector, the NioSelectorPool will also try and
                // close the selector. Try and avoid the ClosedSelectorException
                // although because multiple threads are involved there is always
                // the possibility of an Exception here.
                if (selector.isOpen()) {
                    try {
                        // Cancels all remaining keys
                        selector.selectNow();
                    }catch( Exception ignore ) {
                        if (log.isDebugEnabled())log.debug("",ignore);
                    }
                }
                try {
                    selector.close();
                }catch( Exception ignore ) {
                    if (log.isDebugEnabled())log.debug("",ignore);
                }
            }

    // load() 完成后,即初始化完成,接下来是调用 start() 的过程!让我们回到 Bootstrap 实例:
    // 其实就是对 daemon.start(); 走线问题处理! 

        /**
         * Start the Catalina daemon.
         * @throws Exception Fatal start error
         */
        public void start()
            throws Exception {
            if( catalinaDaemon==null ) init();  // 为确保万无一失,再次检查初始化
    
            Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
            method.invoke(catalinaDaemon, (Object [])null);  // 同样,使用反射调用 Catalina.start();
    
        }
    
    // org.apache.catalina.startup.Catalina.start()
        /**
         * Start a new server instance.
         */
        public void start() {
    
            if (getServer() == null) {
                load();
            }
    
            // 如果经过前面的server初始化,还是获取不到 StandardServer
            if (getServer() == null) {
                log.fatal("Cannot start server. Server instance is not configured.");
                return;
            }
    
            long t1 = System.nanoTime();
    
            // Start the new server
            try {
                // 调用 server.start(), 即是 StandardServer.start(); 同样走一个生命周期的管理过程!
                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 注册关闭钩子,进行资源清理,server stop
            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();
            }
        }
        

     start() 的生命周期管理相比 init() 来说,复杂了一些些!LifeCycleBase.start()

        @Override
        public final synchronized void start() throws LifecycleException {
    
            // 没有准备好时,失败返回
            if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
                    LifecycleState.STARTED.equals(state)) {
    
                if (log.isDebugEnabled()) {
                    Exception e = new LifecycleException();
                    log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
                } else if (log.isInfoEnabled()) {
                    log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
                }
    
                return;
            }
    
            // 没有初始化过的,再次初始化, 这也体现了代码的健壮性,而如果失败,则停止退出
            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()
                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) {
                // This is an 'uncontrolled' failure so put the component into the
                // FAILED state and throw an exception.
                ExceptionUtils.handleThrowable(t);
                setStateInternal(LifecycleState.FAILED, null, false);
                throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
            }
        }

    而 StandardServer.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);
    
            globalNamingResources.start();  // 同样,先调用 NamingResource 的生命周期 start(),事情不多,主要是设置一个可监听点, 再调用 service.start()
    
            // Start our defined Services, standardService.start()
            synchronized (servicesLock) {
                for (int i = 0; i < services.length; i++) {
                    services[i].start();
                }
            }
        }


      tomcat 中 默认的监听器有以下几个,望文生义,可以自行注册监听
        - org.apache.catalina.core.NamingContextListener
        - org.apache.catalina.startup.VersionLoggerListener
        - org.apache.catalina.core.AprLifecycleListener
        - org.apache.catalina.core.JreMemoryLeakPreventionListener
        - org.apache.catalina.mbeans.GlobalResourcesLifecycleListener
        - org.apache.catalina.core.ThreadLocalLeakPreventionListener

    StandardService.startInternal(), 处理整个service的整体流程,包括 StandardEngine的启动和Connector的启动(关键)!

        /**
         * 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()}.
         *
         * @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, 先把 StandardEngine.start() 启起来
            if (engine != null) {
                synchronized (engine) {
                    engine.start();
                }
            }
    
            // 再将Executors启起来,以备请求使用
            synchronized (executors) {
                for (Executor executor: executors) {
                    executor.start();
                }
            }
    
            // 启动mapperListner, 在 init() 时无用,直接在这个时候进行解析
            mapperListener.start();
    
            // Start our defined Connectors second
            // 最后,启动 connectors
            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);
                    }
                }
            }
        }
    
        // StandardEngine.startInternal()
        @Override
        protected synchronized void startInternal() throws LifecycleException {
    
            // Start our subordinate components, if any
            logger = null;
            getLogger();
            // 集群? 看起来很高大上呢! 一般为空
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).start();
            }
            // realm 验证,这里会触发初始化
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).start();
            }
    
            // Start our child containers, if any
            // 将 child 交给启动线程异步执行去
            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());
            }
    
            // 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();
        }
        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();
    
        }
        

    监听器的启动

        // org.apache.catalina.mapper.MapperListener
        @Override
        public void startInternal() throws LifecycleException {
    
            setState(LifecycleState.STARTING);
    
            Engine engine = service.getContainer();
            if (engine == null) {
                return;
            }
    
            findDefaultHost();
    
            addListeners(engine);
    
            Container[] conHosts = engine.findChildren();
            // 注册 host
            for (Container conHost : conHosts) {
                Host host = (Host) conHost;
                if (!LifecycleState.NEW.equals(host.getState())) {
                    // Registering the host will register the context and wrappers
                    registerHost(host);
                }
            }
        }
        // 注册监听到 container 中, 以便收到事件通知, 使用 CopyOnWriteArrayList 数据结构保持监听者
        private void addListeners(Container container) {
            container.addContainerListener(this);
            container.addLifecycleListener(this);
            for (Container child : container.findChildren()) {
                addListeners(child);
            }
        }

    最后,是 connector 的启动过程,主要是依赖协议的实现,主要任务有:启动 Acceptor, Poller 接收请求:

        // Connector
        /**
         * Begin processing requests via this Connector.
         *
         * @exception LifecycleException if a fatal startup error occurs
         */
        @Override
        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 {
                // 可以查看 Http11NioProtocol.start()
                protocolHandler.start();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
            }
        }
        // Http11NioProtocol.start()
        @Override
        public void start() throws Exception {
            if (getLog().isInfoEnabled()) {
                getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
            }
    
            // start() 事件通知到 NioEndpoint
            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();
        }
        // AbstractEndpoint.start()
        public final void start() throws Exception {
            // 在初始化时可能已经完成绑定,此处可能无需执行
            if (bindState == BindState.UNBOUND) {
                bind();
                bindState = BindState.BOUND_ON_START;
            }
            // 更重要的是要创建 Acceptor 和 Pollers
            startInternal();
        }
        // NioEndpoint.startInternal()
        /**
         * Start the NIO endpoint, creating acceptor, poller threads.
         */
        @Override
        public void startInternal() throws Exception {
    
            // 只会执行一次
            if (!running) {
                running = true;
                paused = false;
    
                // 默认128, tomcat8 设置 500
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                                socketProperties.getEventCache());
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
    
                // Create worker collection
                // 初次运行,创建 executors, 后续直接调用
                if ( getExecutor() == null ) {
                    createExecutor();
                }
    
                // 初始化最大连接数锁,tomcat8中默认为 10000
                initializeConnectionLatch();
    
                // Start poller threads
                // 最后,开启 n 个 Poller 处理; 默认为 2
                pollers = new Poller[getPollerThreadCount()];
                for (int i=0; i<pollers.length; i++) {
                    pollers[i] = new Poller();
                    Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                    pollerThread.setPriority(threadPriority);
                    pollerThread.setDaemon(true);
                    pollerThread.start();
                }
    
                // 最后,开启 Acceptor 监听
                startAcceptorThreads();
            }
        }
        // AbstractNioEndpoint
        public void createExecutor() {
            internalExecutor = true;
            // 队列基于 LinkedBlockingQueue, 即无限队列,但是又不是完全的 无限队列,如下实现
            TaskQueue taskqueue = new TaskQueue();
            TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
            // 线程池: 最小默认 10, 最大默认: 200, 
            executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
            taskqueue.setParent( (ThreadPoolExecutor) executor);
        }
        // taskqueue 的 队列插入与出队
        @Override
        public boolean offer(Runnable o) {
          //we can't do any checks
            if (parent==null) return super.offer(o);
            //we are maxed out on threads, simply queue the object
            if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(o);
            //we have idle threads, just add it to the queue
            // 如果当前有空闲线程,则直接入队,使用空闲线程处理即可,而如果按照原生 ThreadPoolExecutor 的逻辑,它会创建到 min 的线程时才会使用队列
            if (parent.getSubmittedCount()<=(parent.getPoolSize())) return super.offer(o);
            //if we have less threads than maximum force creation of a new thread
            if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;
            //if we reached here, we need to add it to the queue
            return super.offer(o);
        }
        @Override
        public Runnable poll(long timeout, TimeUnit unit)
                throws InterruptedException {
            Runnable runnable = super.poll(timeout, unit);
            if (runnable == null && parent != null) {
                // the poll timed out, it gives an opportunity to stop the current
                // thread if needed to avoid memory leaks.
                parent.stopCurrentThreadIfNeeded();
            }
            return runnable;
        }

    接收 http 请求的 poller 处理逻辑如下:

        // NioEndpoint$Poller, 与前面的 BlockPoller 有点区别
            /**
             * The background thread that adds sockets to the Poller, checks the
             * poller for triggered events and hands the associated socket off to an
             * appropriate processor as events occur.
             */
            @Override
            public void run() {
                // Loop until destroy() is called
                while (true) {
    
                    boolean hasEvents = false;
    
                    try {
                        if (!close) {
                            hasEvents = events();
                            if (wakeupCounter.getAndSet(-1) > 0) {
                                //if we are here, means we have other stuff to do
                                //do a non blocking select
                                keyCount = selector.selectNow();
                            } else {
                                keyCount = selector.select(selectorTimeout);
                            }
                            wakeupCounter.set(0);
                        }
                        if (close) {
                            events();
                            timeout(0, false);
                            try {
                                selector.close();
                            } catch (IOException ioe) {
                                log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                            }
                            break;
                        }
                    } catch (Throwable x) {
                        ExceptionUtils.handleThrowable(x);
                        log.error("",x);
                        continue;
                    }
                    //either we timed out or we woke up, process events first
                    if ( keyCount == 0 ) hasEvents = (hasEvents | events());
    
                    Iterator<SelectionKey> iterator =
                        keyCount > 0 ? selector.selectedKeys().iterator() : null;
                    // Walk through the collection of ready keys and dispatch
                    // any active event.
                    while (iterator != null && iterator.hasNext()) {
                        SelectionKey sk = iterator.next();
                        NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
                        // Attachment may be null if another thread has called
                        // cancelledKey()
                        if (attachment == null) {
                            iterator.remove();
                        } else {
                            iterator.remove();
                            processKey(sk, attachment);
                        }
                    }//while
    
                    //process timeouts
                    timeout(keyCount,hasEvents);
                }//while
    
                getStopLatch().countDown();
            }
        // NioEndpoint$Poller, 与前面的 BlockPoller 有点区别
            /**
             * The background thread that adds sockets to the Poller, checks the
             * poller for triggered events and hands the associated socket off to an
             * appropriate processor as events occur.
             */
            @Override
            public void run() {
                // Loop until destroy() is called
                while (true) {
    
                    boolean hasEvents = false;
    
                    try {
                        if (!close) {
                            hasEvents = events();
                            if (wakeupCounter.getAndSet(-1) > 0) {
                                //if we are here, means we have other stuff to do
                                //do a non blocking select
                                keyCount = selector.selectNow();
                            } else {
                                keyCount = selector.select(selectorTimeout);
                            }
                            wakeupCounter.set(0);
                        }
                        if (close) {
                            events();
                            timeout(0, false);
                            try {
                                selector.close();
                            } catch (IOException ioe) {
                                log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                            }
                            break;
                        }
                    } catch (Throwable x) {
                        ExceptionUtils.handleThrowable(x);
                        log.error("",x);
                        continue;
                    }
                    //either we timed out or we woke up, process events first
                    if ( keyCount == 0 ) hasEvents = (hasEvents | events());
    
                    Iterator<SelectionKey> iterator =
                        keyCount > 0 ? selector.selectedKeys().iterator() : null;
                    // Walk through the collection of ready keys and dispatch
                    // any active event.
                    while (iterator != null && iterator.hasNext()) {
                        SelectionKey sk = iterator.next();
                        NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
                        // Attachment may be null if another thread has called
                        // cancelledKey()
                        if (attachment == null) {
                            iterator.remove();
                        } else {
                            iterator.remove();
                            processKey(sk, attachment);
                        }
                    }//while
    
                    //process timeouts
                    timeout(keyCount,hasEvents);
                }//while
    
                getStopLatch().countDown();
            }

    最后,开启 Acceptor 监听, 默认为 1

        protected final void startAcceptorThreads() {
            int count = getAcceptorThreadCount();
            acceptors = new Acceptor[count];
    
            for (int i = 0; i < count; i++) {
                acceptors[i] = createAcceptor();
                String threadName = getName() + "-Acceptor-" + i;
                acceptors[i].setThreadName(threadName);
                Thread t = new Thread(acceptors[i], threadName);
                t.setPriority(getAcceptorThreadPriority());
                t.setDaemon(getDaemon());
                t.start();
            }
        }
        
        @Override
        protected AbstractEndpoint.Acceptor createAcceptor() {
            return new Acceptor();
        }
        // Acceptor 是 NioEndpoint的内部类, 其处理逻辑如下
        // 主要功能为: 1. 负责接入所有的请求处理进行分发; 2. 负责hold处超出最大连接的请求    
            @Override
            public void run() {
    
                int errorDelay = 0;
    
                // Loop until we receive a shutdown command
                while (running) {
    
                    // Loop if endpoint is paused
                    while (paused && running) {
                        state = AcceptorState.PAUSED;
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
    
                    if (!running) {
                        break;
                    }
                    state = AcceptorState.RUNNING;
    
                    try {
                        //if we have reached max connections, wait
                        countUpOrAwaitConnection();
    
                        SocketChannel socket = null;
                        try {
                            // Accept the next incoming connection from the server
                            // socket
                            socket = serverSock.accept();
                        } catch (IOException ioe) {
                            // We didn't get a socket
                            countDownConnection();
                            if (running) {
                                // Introduce delay if necessary
                                errorDelay = handleExceptionWithDelay(errorDelay);
                                // re-throw
                                throw ioe;
                            } else {
                                break;
                            }
                        }
                        // Successful accept, reset the error delay
                        errorDelay = 0;
    
                        // Configure the socket
                        if (running && !paused) {
                            // setSocketOptions() will hand the socket off to
                            // an appropriate processor if successful
                            if (!setSocketOptions(socket)) {
                                closeSocket(socket);
                            }
                        } else {
                            closeSocket(socket);
                        }
                    } catch (Throwable t) {
                        ExceptionUtils.handleThrowable(t);
                        log.error(sm.getString("endpoint.accept.fail"), t);
                    }
                }
                state = AcceptorState.ENDED;
            }

    接到请求后交由外部类简单解析处理:

        /**
         * Process the specified connection.
         * @param socket The socket channel
         * @return <code>true</code> if the socket was correctly configured
         *  and processing may continue, <code>false</code> if the socket needs to be
         *  close immediately
         */
        protected boolean setSocketOptions(SocketChannel socket) {
            // Process the connection
            try {
                //disable blocking, APR style, we are gonna be polling it
                socket.configureBlocking(false);
                Socket sock = socket.socket();
                socketProperties.setProperties(sock);
    
                NioChannel channel = nioChannels.pop();
                if (channel == null) {
                    SocketBufferHandler bufhandler = new SocketBufferHandler(
                            socketProperties.getAppReadBufSize(),
                            socketProperties.getAppWriteBufSize(),
                            socketProperties.getDirectBuffer());
                    if (isSSLEnabled()) {
                        channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
                    } else {
                        channel = new NioChannel(socket, bufhandler);
                    }
                } else {
                    channel.setIOChannel(socket);
                    channel.reset();
                }
                getPoller0().register(channel);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                try {
                    log.error("",t);
                } catch (Throwable tt) {
                    ExceptionUtils.handleThrowable(tt);
                }
                // Tell to close the socket
                return false;
            }
            return true;
        }

      如上,整个启动过程就差不多了!还剩点关闭脚本,回到 Catalina: 

            // 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);
                }
            }
           // 等待关闭信号,通过等socket信号来处理,否则一直循环等待,不停止 main() 线程
            if (await) {
                await();
                stop();
            }

    下面是请求流程的开始:

    // 接收请求是: org.apache.tomcat.util.net.NioEndpoint$Acceptor
    // 接收到后, NioEndpoint.setSocketOptions(SocketChannel socket)
    // 注册处理事件 NioEndpoint$Poller.register(final NioChannel socket)
    // NioEndpoint$Poller.doRun 进行事件处理

            /**
             * Registers a newly created socket with the poller.
             *
             * @param socket    The newly created socket
             */
            public void register(final NioChannel socket) {
                socket.setPoller(this);
                NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
                socket.setSocketWrapper(ka);
                ka.setPoller(this);
                ka.setReadTimeout(getSocketProperties().getSoTimeout());
                ka.setWriteTimeout(getSocketProperties().getSoTimeout());
                ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
                ka.setSecure(isSSLEnabled());
                ka.setReadTimeout(getConnectionTimeout());
                ka.setWriteTimeout(getConnectionTimeout());
                PollerEvent r = eventCache.pop();
                ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
                if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
                else r.reset(socket,ka,OP_REGISTER);
                addEvent(r);
            }
        
            // 添加到事件Poller 队列, 并唤醒处理 selector
            private void addEvent(PollerEvent event) {
                events.offer(event);
                if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
            }
            
    // 后台消费队列, org.apache.tomcat.util.net.NioEndpoint$Poller 
    
            /**
             * The background thread that adds sockets to the Poller, checks the
             * poller for triggered events and hands the associated socket off to an
             * appropriate processor as events occur.
             */
            @Override
            public void run() {
                // Loop until destroy() is called
                while (true) {
    
                    boolean hasEvents = false;
    
                    try {
                        if (!close) {
                            hasEvents = events();
                            if (wakeupCounter.getAndSet(-1) > 0) {
                                //if we are here, means we have other stuff to do
                                //do a non blocking select
                                keyCount = selector.selectNow();
                            } else {
                                keyCount = selector.select(selectorTimeout);
                            }
                            wakeupCounter.set(0);
                        }
                        if (close) {
                            events();
                            timeout(0, false);
                            try {
                                selector.close();
                            } catch (IOException ioe) {
                                log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
                            }
                            break;
                        }
                    } catch (Throwable x) {
                        ExceptionUtils.handleThrowable(x);
                        log.error("",x);
                        continue;
                    }
                    //either we timed out or we woke up, process events first
                    if ( keyCount == 0 ) hasEvents = (hasEvents | events());
    
                    Iterator<SelectionKey> iterator =
                        keyCount > 0 ? selector.selectedKeys().iterator() : null;
                    // Walk through the collection of ready keys and dispatch
                    // any active event.
                    while (iterator != null && iterator.hasNext()) {
                        SelectionKey sk = iterator.next();
                        NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
                        // Attachment may be null if another thread has called
                        // cancelledKey()
                        if (attachment == null) {
                            iterator.remove();
                        } else {
                            iterator.remove();
                            processKey(sk, attachment);
                        }
                    }//while
    
                    //process timeouts
                    timeout(keyCount,hasEvents);
                }//while
    
                getStopLatch().countDown();
            }
    
            // NioEndpoint$Poller.timeout()
            protected void timeout(int keyCount, boolean hasEvents) {
                long now = System.currentTimeMillis();
                // This method is called on every loop of the Poller. Don't process
                // timeouts on every loop of the Poller since that would create too
                // much load and timeouts can afford to wait a few seconds.
                // However, do process timeouts if any of the following are true:
                // - the selector simply timed out (suggests there isn't much load)
                // - the nextExpiration time has passed
                // - the server socket is being closed
                if (nextExpiration > 0 && (keyCount > 0 || hasEvents) && (now < nextExpiration) && !close) {
                    return;
                }
                //timeout
                int keycount = 0;
                try {
                    for (SelectionKey key : selector.keys()) {
                        keycount++;
                        try {
                            NioSocketWrapper ka = (NioSocketWrapper) key.attachment();
                            if ( ka == null ) {
                                cancelledKey(key); //we don't support any keys without attachments
                            } else if (close) {
                                key.interestOps(0);
                                ka.interestOps(0); //avoid duplicate stop calls
                                processKey(key,ka);
                            } else if ((ka.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ ||
                                      (ka.interestOps()&SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
                                boolean isTimedOut = false;
                                // Check for read timeout
                                if ((ka.interestOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
                                    long delta = now - ka.getLastRead();
                                    long timeout = ka.getReadTimeout();
                                    isTimedOut = timeout > 0 && delta > timeout;
                                }
                                // Check for write timeout
                                if (!isTimedOut && (ka.interestOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
                                    long delta = now - ka.getLastWrite();
                                    long timeout = ka.getWriteTimeout();
                                    isTimedOut = timeout > 0 && delta > timeout;
                                }
                                if (isTimedOut) {
                                    key.interestOps(0);
                                    ka.interestOps(0); //avoid duplicate timeout calls
                                    ka.setError(new SocketTimeoutException());
                                    // 提交 excutor 执行逻辑,如交由框架处理
                                    if (!processSocket(ka, SocketEvent.ERROR, true)) {
                                        cancelledKey(key);
                                    }
                                }
                            }
                        }catch ( CancelledKeyException ckx ) {
                            cancelledKey(key);
                        }
                    }//for
                } catch (ConcurrentModificationException cme) {
                    // See https://bz.apache.org/bugzilla/show_bug.cgi?id=57943
                    log.warn(sm.getString("endpoint.nio.timeoutCme"), cme);
                }
                long prevExp = nextExpiration; //for logging purposes only
                nextExpiration = System.currentTimeMillis() +
                        socketProperties.getTimeoutInterval();
                if (log.isTraceEnabled()) {
                    log.trace("timeout completed: keys processed=" + keycount +
                            "; now=" + now + "; nextExpiration=" + prevExp +
                            "; keyCount=" + keyCount + "; hasEvents=" + hasEvents +
                            "; eval=" + ((now < prevExp) && (keyCount>0 || hasEvents) && (!close) ));
                }
    
            }
        }


    // 处理业务逻辑 org.apache.tomcat.util.net.AbstractEndpoint.processSocket()

        /**
         * Process the given SocketWrapper with the given status. Used to trigger
         * processing as if the Poller (for those endpoints that have one)
         * selected the socket.
         *
         * @param socketWrapper The socket wrapper to process
         * @param event         The socket event to be processed
         * @param dispatch      Should the processing be performed on a new
         *                          container thread
         *
         * @return if processing was triggered successfully
         */
        public boolean processSocket(SocketWrapperBase<S> socketWrapper,
                SocketEvent event, boolean dispatch) {
            try {
                if (socketWrapper == null) {
                    return false;
                }
                // 此处获取处理线程,即: org.apache.tomcat.util.net.NioEndpoint$SocketProcessor
                SocketProcessorBase<S> sc = processorCache.pop();
                if (sc == null) {
                    sc = createSocketProcessor(socketWrapper, event);
                } else {
                    sc.reset(socketWrapper, event);
                }
                Executor executor = getExecutor();
                // 如果有线程池,就异步处理,否则同步调用
                if (dispatch && executor != null) {
                    executor.execute(sc);
                } else {
                    sc.run();
                }
            } catch (RejectedExecutionException ree) {
                getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
                return false;
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                // This means we got an OOM or similar creating a thread, or that
                // the pool and its queue are full
                getLog().error(sm.getString("endpoint.process.fail"), t);
                return false;
            }
            return true;
        }


    // org.apache.tomcat.util.net.SocketProcessorBase 处理 run(), 子类实现 doRun() 方法。

        @Override
        public final void run() {
            synchronized (socketWrapper) {
                // It is possible that processing may be triggered for read and
                // write at the same time. The sync above makes sure that processing
                // does not occur in parallel. The test below ensures that if the
                // first event to be processed results in the socket being closed,
                // the subsequent events are not processed.
                if (socketWrapper.isClosed()) {
                    return;
                }
                doRun();
            }
        }
        
    
    // NioEndpoint$SocketProcessor 处理逻辑 
        /**
         * This class is the equivalent of the Worker, but will simply use in an
         * external Executor thread pool.
         */
        protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
    
            public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
                super(socketWrapper, event);
            }
    
            @Override
            protected void doRun() {
                NioChannel socket = socketWrapper.getSocket();
                SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
    
                try {
                    int handshake = -1;
    
                    try {
                        if (key != null) {
                            if (socket.isHandshakeComplete()) {
                                // No TLS handshaking required. Let the handler
                                // process this socket / event combination.
                                handshake = 0;
                            } else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
                                    event == SocketEvent.ERROR) {
                                // Unable to complete the TLS handshake. Treat it as
                                // if the handshake failed.
                                handshake = -1;
                            } else {
                                handshake = socket.handshake(key.isReadable(), key.isWritable());
                                // The handshake process reads/writes from/to the
                                // socket. status may therefore be OPEN_WRITE once
                                // the handshake completes. However, the handshake
                                // happens when the socket is opened so the status
                                // must always be OPEN_READ after it completes. It
                                // is OK to always set this as it is only used if
                                // the handshake completes.
                                event = SocketEvent.OPEN_READ;
                            }
                        }
                    } catch (IOException x) {
                        handshake = -1;
                        if (log.isDebugEnabled()) log.debug("Error during SSL handshake",x);
                    } catch (CancelledKeyException ckx) {
                        handshake = -1;
                    }
                    if (handshake == 0) {
                        SocketState state = SocketState.OPEN;
                        // Process the request from this socket
                        // 转交控控权给业务系统
                        if (event == null) {
                            state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
                        } else {
                            state = getHandler().process(socketWrapper, event);
                        }
                        if (state == SocketState.CLOSED) {
                            close(socket, key);
                        }
                    } else if (handshake == -1 ) {
                        close(socket, key);
                    } else if (handshake == SelectionKey.OP_READ){
                        socketWrapper.registerReadInterest();
                    } else if (handshake == SelectionKey.OP_WRITE){
                        socketWrapper.registerWriteInterest();
                    }
                } catch (CancelledKeyException cx) {
                    socket.getPoller().cancelledKey(key);
                } catch (VirtualMachineError vme) {
                    ExceptionUtils.handleThrowable(vme);
                } catch (Throwable t) {
                    log.error("", t);
                    socket.getPoller().cancelledKey(key);
                } finally {
                    socketWrapper = null;
                    event = null;
                    //return to cache
                    if (running && !paused) {
                        processorCache.push(this);
                    }
                }
            }
        }
        
    // org.apache.coyote.AbstractProtocol$ConnectionHandler  -> 获取到
            @Override
            public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
                if (getLog().isDebugEnabled()) {
                    getLog().debug(sm.getString("abstractConnectionHandler.process",
                            wrapper.getSocket(), status));
                }
                if (wrapper == null) {
                    // Nothing to do. Socket has been closed.
                    return SocketState.CLOSED;
                }
    
                S socket = wrapper.getSocket();
    
                Processor processor = connections.get(socket);
                if (getLog().isDebugEnabled()) {
                    getLog().debug(sm.getString("abstractConnectionHandler.connectionsGet",
                            processor, socket));
                }
    
                // Async timeouts are calculated on a dedicated thread and then
                // dispatched. Because of delays in the dispatch process, the
                // timeout may no longer be required. Check here and avoid
                // unnecessary processing.
                if (SocketEvent.TIMEOUT == status && (processor == null ||
                        !processor.isAsync() || !processor.checkAsyncTimeoutGeneration())) {
                    // This is effectively a NO-OP
                    return SocketState.OPEN;
                }
    
                if (processor != null) {
                    // Make sure an async timeout doesn't fire
                    getProtocol().removeWaitingProcessor(processor);
                } else if (status == SocketEvent.DISCONNECT || status == SocketEvent.ERROR) {
                    // Nothing to do. Endpoint requested a close and there is no
                    // longer a processor associated with this socket.
                    return SocketState.CLOSED;
                }
    
                ContainerThreadMarker.set();
    
                try {
                    if (processor == null) {
                        String negotiatedProtocol = wrapper.getNegotiatedProtocol();
                        if (negotiatedProtocol != null) {
                            UpgradeProtocol upgradeProtocol =
                                    getProtocol().getNegotiatedProtocol(negotiatedProtocol);
                            if (upgradeProtocol != null) {
                                processor = upgradeProtocol.getProcessor(
                                        wrapper, getProtocol().getAdapter());
                            } else if (negotiatedProtocol.equals("http/1.1")) {
                                // Explicitly negotiated the default protocol.
                                // Obtain a processor below.
                            } else {
                                // TODO:
                                // OpenSSL 1.0.2's ALPN callback doesn't support
                                // failing the handshake with an error if no
                                // protocol can be negotiated. Therefore, we need to
                                // fail the connection here. Once this is fixed,
                                // replace the code below with the commented out
                                // block.
                                if (getLog().isDebugEnabled()) {
                                    getLog().debug(sm.getString(
                                        "abstractConnectionHandler.negotiatedProcessor.fail",
                                        negotiatedProtocol));
                                }
                                return SocketState.CLOSED;
                                /*
                                 * To replace the code above once OpenSSL 1.1.0 is
                                 * used.
                                // Failed to create processor. This is a bug.
                                throw new IllegalStateException(sm.getString(
                                        "abstractConnectionHandler.negotiatedProcessor.fail",
                                        negotiatedProtocol));
                                */
                            }
                        }
                    }
                    if (processor == null) {
                        processor = recycledProcessors.pop();
                        if (getLog().isDebugEnabled()) {
                            getLog().debug(sm.getString("abstractConnectionHandler.processorPop",
                                    processor));
                        }
                    }
                    if (processor == null) {
                        processor = getProtocol().createProcessor();
                        register(processor);
                    }
    
                    processor.setSslSupport(
                            wrapper.getSslSupport(getProtocol().getClientCertProvider()));
    
                    // Associate the processor with the connection
                    connections.put(socket, processor);
    
                    SocketState state = SocketState.CLOSED;
                    do {
                        state = processor.process(wrapper, status);
    
                        if (state == SocketState.UPGRADING) {
                            // Get the HTTP upgrade handler
                            UpgradeToken upgradeToken = processor.getUpgradeToken();
                            // Retrieve leftover input
                            ByteBuffer leftOverInput = processor.getLeftoverInput();
                            if (upgradeToken == null) {
                                // Assume direct HTTP/2 connection
                                UpgradeProtocol upgradeProtocol = getProtocol().getUpgradeProtocol("h2c");
                                if (upgradeProtocol != null) {
                                    processor = upgradeProtocol.getProcessor(
                                            wrapper, getProtocol().getAdapter());
                                    wrapper.unRead(leftOverInput);
                                    // Associate with the processor with the connection
                                    connections.put(socket, processor);
                                } else {
                                    if (getLog().isDebugEnabled()) {
                                        getLog().debug(sm.getString(
                                            "abstractConnectionHandler.negotiatedProcessor.fail",
                                            "h2c"));
                                    }
                                    return SocketState.CLOSED;
                                }
                            } else {
                                HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
                                // Release the Http11 processor to be re-used
                                release(processor);
                                // Create the upgrade processor
                                processor = getProtocol().createUpgradeProcessor(wrapper, upgradeToken);
                                if (getLog().isDebugEnabled()) {
                                    getLog().debug(sm.getString("abstractConnectionHandler.upgradeCreate",
                                            processor, wrapper));
                                }
                                wrapper.unRead(leftOverInput);
                                // Mark the connection as upgraded
                                wrapper.setUpgraded(true);
                                // Associate with the processor with the connection
                                connections.put(socket, processor);
                                // Initialise the upgrade handler (which may trigger
                                // some IO using the new protocol which is why the lines
                                // above are necessary)
                                // This cast should be safe. If it fails the error
                                // handling for the surrounding try/catch will deal with
                                // it.
                                if (upgradeToken.getInstanceManager() == null) {
                                    httpUpgradeHandler.init((WebConnection) processor);
                                } else {
                                    ClassLoader oldCL = upgradeToken.getContextBind().bind(false, null);
                                    try {
                                        httpUpgradeHandler.init((WebConnection) processor);
                                    } finally {
                                        upgradeToken.getContextBind().unbind(false, oldCL);
                                    }
                                }
                            }
                        }
                    } while ( state == SocketState.UPGRADING);
    
                    if (state == SocketState.LONG) {
                        // In the middle of processing a request/response. Keep the
                        // socket associated with the processor. Exact requirements
                        // depend on type of long poll
                        longPoll(wrapper, processor);
                        if (processor.isAsync()) {
                            getProtocol().addWaitingProcessor(processor);
                        }
                    } else if (state == SocketState.OPEN) {
                        // In keep-alive but between requests. OK to recycle
                        // processor. Continue to poll for the next request.
                        connections.remove(socket);
                        release(processor);
                        wrapper.registerReadInterest();
                    } else if (state == SocketState.SENDFILE) {
                        // Sendfile in progress. If it fails, the socket will be
                        // closed. If it works, the socket either be added to the
                        // poller (or equivalent) to await more data or processed
                        // if there are any pipe-lined requests remaining.
                    } else if (state == SocketState.UPGRADED) {
                        // Don't add sockets back to the poller if this was a
                        // non-blocking write otherwise the poller may trigger
                        // multiple read events which may lead to thread starvation
                        // in the connector. The write() method will add this socket
                        // to the poller if necessary.
                        if (status != SocketEvent.OPEN_WRITE) {
                            longPoll(wrapper, processor);
                        }
                    } else if (state == SocketState.SUSPENDED) {
                        // Don't add sockets back to the poller.
                        // The resumeProcessing() method will add this socket
                        // to the poller.
                    } else {
                        // Connection closed. OK to recycle the processor. Upgrade
                        // processors are not recycled.
                        connections.remove(socket);
                        if (processor.isUpgrade()) {
                            UpgradeToken upgradeToken = processor.getUpgradeToken();
                            HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
                            InstanceManager instanceManager = upgradeToken.getInstanceManager();
                            if (instanceManager == null) {
                                httpUpgradeHandler.destroy();
                            } else {
                                ClassLoader oldCL = upgradeToken.getContextBind().bind(false, null);
                                try {
                                    httpUpgradeHandler.destroy();
                                } finally {
                                    try {
                                        instanceManager.destroyInstance(httpUpgradeHandler);
                                    } catch (Throwable e) {
                                        ExceptionUtils.handleThrowable(e);
                                        getLog().error(sm.getString("abstractConnectionHandler.error"), e);
                                    }
                                    upgradeToken.getContextBind().unbind(false, oldCL);
                                }
                            }
                        } else {
                            release(processor);
                        }
                    }
                    return state;
                } catch(java.net.SocketException e) {
                    // SocketExceptions are normal
                    getLog().debug(sm.getString(
                            "abstractConnectionHandler.socketexception.debug"), e);
                } catch (java.io.IOException e) {
                    // IOExceptions are normal
                    getLog().debug(sm.getString(
                            "abstractConnectionHandler.ioexception.debug"), e);
                } catch (ProtocolException e) {
                    // Protocol exceptions normally mean the client sent invalid or
                    // incomplete data.
                    getLog().debug(sm.getString(
                            "abstractConnectionHandler.protocolexception.debug"), e);
                }
                // Future developers: if you discover any other
                // rare-but-nonfatal exceptions, catch them here, and log as
                // above.
                catch (Throwable e) {
                    ExceptionUtils.handleThrowable(e);
                    // any other exception or error is odd. Here we log it
                    // with "ERROR" level, so it will show up even on
                    // less-than-verbose logs.
                    getLog().error(sm.getString("abstractConnectionHandler.error"), e);
                } finally {
                    ContainerThreadMarker.clear();
                }
    
                // Make sure socket/processor is removed from the list of current
                // connections
                connections.remove(socket);
                release(processor);
                return SocketState.CLOSED;
            }
    
    
    // org.apache.coyote.http11.Http11Processor -> org.apache.coyote.AbstractProcessorLight
        @Override
        public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
                throws IOException {
    
            SocketState state = SocketState.CLOSED;
            Iterator<DispatchType> dispatches = null;
            do {
                if (dispatches != null) {
                    DispatchType nextDispatch = dispatches.next();
                    state = dispatch(nextDispatch.getSocketStatus());
                } else if (status == SocketEvent.DISCONNECT) {
                    // Do nothing here, just wait for it to get recycled
                } else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
                    state = dispatch(status);
                    if (state == SocketState.OPEN) {
                        // There may be pipe-lined data to read. If the data isn't
                        // processed now, execution will exit this loop and call
                        // release() which will recycle the processor (and input
                        // buffer) deleting any pipe-lined data. To avoid this,
                        // process it now.
                        state = service(socketWrapper);
                    }
                } else if (status == SocketEvent.OPEN_WRITE) {
                    // Extra write event likely after async, ignore
                    state = SocketState.LONG;
                } else if (status == SocketEvent.OPEN_READ){
                    state = service(socketWrapper);
                } else {
                    // Default to closing the socket if the SocketEvent passed in
                    // is not consistent with the current state of the Processor
                    state = SocketState.CLOSED;
                }
    
                if (getLog().isDebugEnabled()) {
                    getLog().debug("Socket: [" + socketWrapper +
                            "], Status in: [" + status +
                            "], State out: [" + state + "]");
                }
    
                if (state != SocketState.CLOSED && isAsync()) {
                    state = asyncPostProcess();
                    if (getLog().isDebugEnabled()) {
                        getLog().debug("Socket: [" + socketWrapper +
                                "], State after async post processing: [" + state + "]");
                    }
                }
    
                if (dispatches == null || !dispatches.hasNext()) {
                    // Only returns non-null iterator if there are
                    // dispatches to process.
                    dispatches = getIteratorAndClearDispatches();
                }
            } while (state == SocketState.ASYNC_END ||
                    dispatches != null && state != SocketState.CLOSED);
    
            return state;
        }
    View Code

      启动过程接口调用时序图如下(图片来源于网络):


         已经很接近了,看到已经走到了service方法,与servlet的service只差一步之遥……

    最后,我们以一个 http 请求的栈跟踪作为结束语吧,从中我可以清楚地看到整个处理线程运行情况!

    "http-apr-8080-exec-7@4763" daemon prio=5 tid=0x30 nid=NA runnable
      java.lang.Thread.State: RUNNABLE
          at com.xxx.controller.HelloController.test(HelloController.java:40)
          at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
          at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
          at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
          at java.lang.reflect.Method.invoke(Method.java:498)
          at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
          at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
          at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
          at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
          at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
          at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
          at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
          at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
          at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
          at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
          at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
          at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
          at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
          at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
          at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
          at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
          at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
          at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2517)
          at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2506)
          - locked <0x13dc> (a org.apache.tomcat.util.net.AprEndpoint$AprSocketWrapper)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
          at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
          at java.lang.Thread.run(Thread.java:745)

    未完,待续...

  • 相关阅读:
    hdu 1028 Ignatius and the Princess III (n的划分)
    CodeForces
    poj 3254 Corn Fields (状压DP入门)
    HYSBZ 1040 骑士 (基环外向树DP)
    PAT 1071 Speech Patterns (25)
    PAT 1077 Kuchiguse (20)
    PAT 1043 Is It a Binary Search Tree (25)
    PAT 1053 Path of Equal Weight (30)
    c++ 常用标准库
    常见数学问题
  • 原文地址:https://www.cnblogs.com/yougewe/p/9775404.html
Copyright © 2011-2022 走看看