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)

    未完,待续...

  • 相关阅读:
    Python 内存泄露 内存回收机制
    decimal 格式化
    iis 6 配置PHP
    按照 in (....) 里面的顺序进行排序
    设计模式之 访问者模式
    与数据库的列信息有关
    win32 IFolderView2::GetCurrentFolderFlags的使用
    MySQL防止重复插入相同记录 insert if not exists
    c++扩展Python(未验证)
    c++ 获取桌面图标的坐标与名称
  • 原文地址:https://www.cnblogs.com/yougewe/p/9775404.html
Copyright © 2011-2022 走看看