上一节中我们分析了通信的建立,既然建立了通信,那么当一个请求发送过来的时候,我们又是怎么去寻找到之前注册好的容器的呢?

connector.getService().getMapper().map(serverName, decodedURI,
                    version, request.getMappingData());

以上代码来自
org.apache.catalina.connector.CoyoteAdapter.postParseRequest(Request, Request, Response, Response)这个方法。可以看到tomcat调用Mapper的map去映射容器

//host是一个消息字节对象,内部维护的是host名
//uri 顾名思义,就是uri
//version 版本
//mappingData映射数据对象,这个类被Request关联,mappingData维护着寻找到的
//Host,Context
public void org.apache.catalina.mapper.Mapper.map(MessageBytes host, MessageBytes uri, String version,
                    MappingData mappingData) throws IOException {

        if (host.isNull()) {
            host.getCharChunk().append(defaultHostName);
        }
        host.toChars();
        uri.toChars();
        internalMap(host.getCharChunk(), uri.getCharChunk(), version,
                mappingData);
    }

internalMap方法就是具体的寻找容器方法

private final void internalMap(CharChunk host, CharChunk uri,
            String version, MappingData mappingData) throws IOException {
        。。。。。。省略部分代码
        uri.setLimit(-1);

        // Virtual host mapping
        MappedHost[] hosts = this.hosts;
        //忽略大小写精确匹配host,内部使用二分法查找
        MappedHost mappedHost = exactFindIgnoreCase(hosts, host);
        if (mappedHost == null) {
            // Note: Internally, the Mapper does not use the leading * on a
            //       wildcard host. This is to allow this shortcut.
            //如果host名是一个通配符开头的*.,那么寻找到第一个点,截取后再次进行精确匹配
            int firstDot = host.indexOf('.');
            if (firstDot > -1) {
                int offset = host.getOffset();
                try {
                    host.setOffset(firstDot + offset);
                    //精确匹配
                    mappedHost = exactFindIgnoreCase(hosts, host);
                } finally {
                    // Make absolutely sure this gets reset
                    //恢复
                    host.setOffset(offset);
                }
            }
            //如果还是没有找到,那么设置默认的host,如果连默认的host都没有,那么直接返回
            if (mappedHost == null) {
                mappedHost = defaultHost;
                if (mappedHost == null) {
                    return;
                }
            }
        }
        //设置Host对象
        mappingData.host = mappedHost.object;

        // Context mapping
        ContextList contextList = mappedHost.contextList;
        MappedContext[] contexts = contextList.contexts;
        //匹配context,匹配方式也是二分法查找,要么找到精确匹配的,要么就是仅次于当前uri路径的context
        int pos = find(contexts, uri);
        if (pos == -1) {
            return;
        }

        int lastSlash = -1;
        int uriEnd = uri.getEnd();
        int length = -1;
        boolean found = false;
        MappedContext context = null;
        while (pos >= 0) {
            //获取匹配到的context
            context = contexts[pos];
            //如果uri路径是以context开头的
            if (uri.startsWith(context.name)) {
                length = context.name.length();
                //长度一样,那好办,已经找到了
                if (uri.getLength() == length) {
                    found = true;
                    break;
                    //如果context.name.length()后面紧跟的就是一个/,那么也表示寻找了
                } else if (uri.startsWithIgnoreCase("/", length)) {
                    found = true;
                    break;
                }
            }
            
            if (lastSlash == -1) {
                //寻找contextList.nesting + 1次/,也就是找到第contextList.nesting个/的位置
                //值得注意的是这个contextList.nesting是指这个集合中context路径最长的,tomcat从最后的/开始往前退
                //直到找到匹配的context路径前缀,比如/test/a/b/c,其中只有一个context,它的路径是/test,那么就会从/test/a/b/c-》
                ///test/a/b/-》/test/a/-》/test/,当然如果还有个路径为/test/a的context,那么这个context优先被匹配
                lastSlash = nthSlash(uri, contextList.nesting + 1);
            } else {
                //从后面往前找到最后一个/的位置
                lastSlash = lastSlash(uri);
            }
            //将uri的messageByte的end设置到最后一个/的位置
            uri.setEnd(lastSlash);
            pos = find(contexts, uri);
        }
        //恢复原始的uri结束位置
        uri.setEnd(uriEnd);
        //如果没有找到,那就看看没有根路径的context,根路径的context如果有,一定是排在第一个位置
        if (!found) {
            if (contexts[0].name.equals("")) {
                context = contexts[0];
            } else {
                context = null;
            }
        }
        //没找到,直接返回
        if (context == null) {
            return;
        }
        //设置context路径
        mappingData.contextPath.setString(context.name);

        ContextVersion contextVersion = null;
        //获取所有的版本
        ContextVersion[] contextVersions = context.versions;
        final int versionCount = contextVersions.length;
        if (versionCount > 1) {
            Context[] contextObjects = new Context[contextVersions.length];
            for (int i = 0; i < contextObjects.length; i++) {
                contextObjects[i] = contextVersions[i].object;
            }
            //给mappingData设置与之contextpath匹配的所有版本的context
            mappingData.contexts = contextObjects;
            if (version != null) {
                //精确匹配版本,找到合适的context
                contextVersion = exactFind(contextVersions, version);
            }
        }
        //如果没有找到,那么就把最后一个版本,也就是最高版本返回
        if (contextVersion == null) {
            // Return the latest version
            // The versions array is known to contain at least one element
            contextVersion = contextVersions[versionCount - 1];
        }
        //设置context
        mappingData.context = contextVersion.object;
        //找到的context的/个数
        mappingData.contextSlashCount = contextVersion.slashCount;

        // Wrapper mapping
        if (!contextVersion.isPaused()) {
            //继续匹配wrapper
            internalMapWrapper(contextVersion, uri, mappingData);
        }

    }

当host和context都找到之后,接下来要寻找的就是wrapper了

private final void org.apache.catalina.mapper.Mapper.internalMapWrapper(ContextVersion contextVersion,
                                          CharChunk path,
                                          MappingData mappingData) throws IOException {

        int pathOffset = path.getOffset();
        int pathEnd = path.getEnd();
        boolean noServletPath = false;
        //context路径长度
        int length = contextVersion.path.length();
        //如果和context路径一样长,那么就表示没有Servlet路径
        if (length == (pathEnd - pathOffset)) {
            noServletPath = true;
        }
        //servletPath的开始路径下标
        int servletPath = pathOffset + length;
        //设置偏移下标
        path.setOffset(servletPath);

        // Rule 1 -- Exact Match  精确匹配
        MappedWrapper[] exactWrappers = contextVersion.exactWrappers;
        //(*1*)
        internalMapExactWrapper(exactWrappers, path, mappingData);

        // Rule 2 -- Prefix Match 前缀匹配
        boolean checkJspWelcomeFiles = false;
        MappedWrapper[] wildcardWrappers = contextVersion.wildcardWrappers;
        if (mappingData.wrapper == null) {
            //(*2*)
            internalMapWildcardWrapper(wildcardWrappers, contextVersion.nesting,
                                       path, mappingData);
            //如果是jsp通配符,并且是根路径,那么说明默认是jsp作为首页
            if (mappingData.wrapper != null && mappingData.jspWildCard) {
                char[] buf = path.getBuffer();
                if (buf[pathEnd - 1] == '/') {
                    /*
                     * Path ending in '/' was mapped to JSP servlet based on
                     * wildcard match (e.g., as specified in url-pattern of a
                     * jsp-property-group.
                     * Force the context's welcome files, which are interpreted
                     * as JSP files (since they match the url-pattern), to be
                     * considered. See Bugzilla 27664.
                     */
                    mappingData.wrapper = null;
                    checkJspWelcomeFiles = true;
                } else {
                    // See Bugzilla 27704
                    mappingData.wrapperPath.setChars(buf, path.getStart(),
                                                     path.getLength());
                    mappingData.pathInfo.recycle();
                }
            }
        }

        if(mappingData.wrapper == null && noServletPath &&
                contextVersion.object.getMapperContextRootRedirectEnabled()) {
            // The path is empty, redirect to "/"
            path.append('/');
            pathEnd = path.getEnd();
            mappingData.redirectPath.setChars
                (path.getBuffer(), pathOffset, pathEnd - pathOffset);
            path.setEnd(pathEnd - 1);
            return;
        }

        // Rule 3 -- Extension Match 扩展名匹配
        MappedWrapper[] extensionWrappers = contextVersion.extensionWrappers;
        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
            //扩展名匹配
            internalMapExtensionWrapper(extensionWrappers, path, mappingData,
                    true);
        }

        // Rule 4 -- Welcome resources processing for servlets
        //当到这里还是没有找到任何wrapper的时候,就考虑使用欢迎页
        if (mappingData.wrapper == null) {
            boolean checkWelcomeFiles = checkJspWelcomeFiles;
            if (!checkWelcomeFiles) {
                char[] buf = path.getBuffer();
                判断是否是以/结尾的,如果是,那么表示需要检查欢迎页
                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
            }
            if (checkWelcomeFiles) {
                //循环遍历每个欢迎首页
                for (int i = 0; (i < contextVersion.welcomeResources.length)
                         && (mappingData.wrapper == null); i++) {
                    path.setOffset(pathOffset);
                    path.setEnd(pathEnd);
                    //补充获取欢迎页的路径
                    path.append(contextVersion.welcomeResources[i], 0,
                            contextVersion.welcomeResources[i].length());
                    path.setOffset(servletPath);

                    // Rule 4a -- Welcome resources processing for exact macth
                    //精确匹配wrapper
                    internalMapExactWrapper(exactWrappers, path, mappingData);

                    // Rule 4b -- Welcome resources processing for prefix match
                    //如果还是没有找到,那么就通过通配符查找
                    if (mappingData.wrapper == null) {
                        internalMapWildcardWrapper
                            (wildcardWrappers, contextVersion.nesting,
                             path, mappingData);
                    }

                    // Rule 4c -- Welcome resources processing
                    //            for physical folder
                    //还是没有
                    if (mappingData.wrapper == null
                        && contextVersion.resources != null) {
                        String pathStr = path.toString();
                        //查看是否存在这样的web资源
                        WebResource file =
                                contextVersion.resources.getResource(pathStr);
                        if (file != null && file.isFile()) {
                            //通过后缀匹配
                            internalMapExtensionWrapper(extensionWrappers, path,
                                                        mappingData, true);
                            //如果还是为空,那么就设置默认的wrapper
                            if (mappingData.wrapper == null
                                && contextVersion.defaultWrapper != null) {
                                mappingData.wrapper =
                                    contextVersion.defaultWrapper.object;
                                mappingData.requestPath.setChars
                                    (path.getBuffer(), path.getStart(),
                                     path.getLength());
                                mappingData.wrapperPath.setChars
                                    (path.getBuffer(), path.getStart(),
                                     path.getLength());
                                mappingData.requestPath.setString(pathStr);
                                mappingData.wrapperPath.setString(pathStr);
                            }
                        }
                    }
                }
                //恢复
                path.setOffset(servletPath);
                path.setEnd(pathEnd);
            }

        }

       //后缀匹配,但是这个后缀匹配第四参数修改为了false,表示我不期望它是个物理资源
        if (mappingData.wrapper == null) {
            boolean checkWelcomeFiles = checkJspWelcomeFiles;
            if (!checkWelcomeFiles) {
                char[] buf = path.getBuffer();
                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
            }
            if (checkWelcomeFiles) {
                for (int i = 0; (i < contextVersion.welcomeResources.length)
                         && (mappingData.wrapper == null); i++) {
                    path.setOffset(pathOffset);
                    path.setEnd(pathEnd);
                    path.append(contextVersion.welcomeResources[i], 0,
                                contextVersion.welcomeResources[i].length());
                    path.setOffset(servletPath);
                    internalMapExtensionWrapper(extensionWrappers, path,
                                                mappingData, false);
                }

                path.setOffset(servletPath);
                path.setEnd(pathEnd);
            }
        }


        // Rule 7 -- Default servlet
        //默认Servlet
        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
            //设置默认的wrapper
            if (contextVersion.defaultWrapper != null) {
                mappingData.wrapper = contextVersion.defaultWrapper.object;
                mappingData.requestPath.setChars
                    (path.getBuffer(), path.getStart(), path.getLength());
                mappingData.wrapperPath.setChars
                    (path.getBuffer(), path.getStart(), path.getLength());
                mappingData.matchType = MappingMatch.DEFAULT;
            }
            // Redirection to a folder
            char[] buf = path.getBuffer();
            if (contextVersion.resources != null && buf[pathEnd -1 ] != '/') {
                String pathStr = path.toString();
                WebResource file;
                // Handle context root
                if (pathStr.length() == 0) {
                    file = contextVersion.resources.getResource("/");
                } else {
                    file = contextVersion.resources.getResource(pathStr);
                }
                if (file != null && file.isDirectory() &&
                        contextVersion.object.getMapperDirectoryRedirectEnabled()) {
                    // Note: this mutates the path: do not do any processing
                    // after this (since we set the redirectPath, there
                    // shouldn't be any)
                    path.setOffset(pathOffset);
                    path.append('/');
                    mappingData.redirectPath.setChars
                        (path.getBuffer(), path.getStart(), path.getLength());
                } else {
                    mappingData.requestPath.setString(pathStr);
                    mappingData.wrapperPath.setString(pathStr);
                }
            }
        }

        path.setOffset(pathOffset);
        path.setEnd(pathEnd);
    }

精确匹配

private final void org.apache.catalina.mapper.Mapper.internalMapExactWrapper
        (MappedWrapper[] wrappers, CharChunk path, MappingData mappingData) {
        //精确匹配
        MappedWrapper wrapper = exactFind(wrappers, path);
        if (wrapper != null) {
            //设置Servlet路径
            mappingData.requestPath.setString(wrapper.name);
            
            mappingData.wrapper = wrapper.object;
            //设置根路径类型
            if (path.equals("/")) {
                // Special handling for Context Root mapped servlet
                mappingData.pathInfo.setString("/");
                mappingData.wrapperPath.setString("");
                // This seems wrong but it is what the spec says...
                mappingData.contextPath.setString("");
                mappingData.matchType = MappingMatch.CONTEXT_ROOT;
            } else {
                mappingData.wrapperPath.setString(wrapper.name);
                //设置精确匹配
                mappingData.matchType = MappingMatch.EXACT;
            }
        }
    }

前缀匹配

private final void internalMapWildcardWrapper
        (MappedWrapper[] wrappers, int nesting, CharChunk path,
         MappingData mappingData) {

        int pathEnd = path.getEnd();

        int lastSlash = -1;
        int length = -1;
        //二分法查找
        int pos = find(wrappers, path);
        if (pos != -1) {
            boolean found = false;
            while (pos >= 0) {
                if (path.startsWith(wrappers[pos].name)) {//   /a/b/c   /a/b/*(在包装wrapper的时候,这个/*会被去掉)
                    length = wrappers[pos].name.length();
                    //和匹配contex一样
                    if (path.getLength() == length) {
                        found = true;
                        break;
                    } else if (path.startsWithIgnoreCase("/", length)) {
                        found = true;
                        break;
                    }
                }
                if (lastSlash == -1) {
                    lastSlash = nthSlash(path, nesting + 1);//获取第nesting个/
                } else {
                    lastSlash = lastSlash(path);//获取最后一个/
                }
                path.setEnd(lastSlash);
                pos = find(wrappers, path);
            }
            //恢复
            path.setEnd(pathEnd);
            if (found) {
                //设置路径
                mappingData.wrapperPath.setString(wrappers[pos].name);
                if (path.getLength() > length) {
                    //设置路径信息,*号通配符代表的路径
                    mappingData.pathInfo.setChars
                        (path.getBuffer(),
                         path.getOffset() + length,
                         path.getLength() - length);
                }
                //设置请求路径
                mappingData.requestPath.setChars
                    (path.getBuffer(), path.getOffset(), path.getLength());
                mappingData.wrapper = wrappers[pos].object;
                mappingData.jspWildCard = wrappers[pos].jspWildCard;
                mappingData.matchType = MappingMatch.PATH;
            }
        }
    }

扩展名匹配

private final void org.apache.catalina.mapper.Mapper.internalMapExtensionWrapper(MappedWrapper[] wrappers,
            CharChunk path, MappingData mappingData, boolean resourceExpected) {
        //路径字符数组
        char[] buf = path.getBuffer();
        //路径最后一个位置
        int pathEnd = path.getEnd();
        //路径的开始偏移
        int servletPath = path.getOffset();
        int slash = -1;
        for (int i = pathEnd - 1; i >= servletPath; i--) {
            if (buf[i] == '/') {
                //扎到最后一个/
                slash = i;
                break;
            }
        }
        //从这个/的位置开始寻找后缀
        if (slash >= 0) {
            int period = -1;
            for (int i = pathEnd - 1; i > slash; i--) {
                if (buf[i] == '.') {
                    period = i;
                    break;
                }
            }
            //如果找到后缀,进行后缀精确匹配
            if (period >= 0) {
                path.setOffset(period + 1);
                path.setEnd(pathEnd);
                MappedWrapper wrapper = exactFind(wrappers, path);
                if (wrapper != null
                        && (resourceExpected || !wrapper.resourceOnly)) {
                    //设置wrapper的路径
                    mappingData.wrapperPath.setChars(buf, servletPath, pathEnd
                            - servletPath);
                    //设置请求路径
                    mappingData.requestPath.setChars(buf, servletPath, pathEnd
                            - servletPath);
                    mappingData.wrapper = wrapper.object;
                    //匹配类型为扩展名匹配
                    mappingData.matchType = MappingMatch.EXTENSION;
                }
                //恢复偏移
                path.setOffset(servletPath);
                path.setEnd(pathEnd);
            }
        }
    }

从上一节的一行代码中可以发现,tomcat是通过排管来进行执行的。首先执行的就是engine的排管,我们不管这个排管中有什么乱七八糟的管道阀,我们一定能够确定的是,engine内部一定有一个基础的管道阀,由于StandardEnginValve,StandardHostValve,StrandardContextValve没有做过多的逻辑,基本上都在判断是支持异步处理,这里我们只分析Wrapper的StandardWrapperValve

 public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        。。。。。。省略部分代码
        // Allocate a servlet instance to process this request
        try {
            if (!unavailable) {
                //获取servlet对象,如果已经创建直接获取(一般是那种onstartup大于零的在StandardContext启动的时候就进行了创建)
                //调用其初始化方法
                servlet = wrapper.allocate();
            }
        } catch (UnavailableException e) {
           。。。。。。省略
        } 
        //获取请求路径消息字节
        MessageBytes requestPathMB = request.getRequestPathMB();
        //请求分发类型
        DispatcherType dispatcherType = DispatcherType.REQUEST;
        //如果支持的是异步分发类型,那么是指分发类型为异步
        if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
        request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
        request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
                requestPathMB);
        // Create the filter chain for this request
        //创建过滤器链
        ApplicationFilterChain filterChain =
                ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        try {
            if ((servlet != null) && (filterChain != null)) {
                // Swallow output if needed
                //这个getSwallowOutput方法的作用,从代码来看是用于捕获线程的输出使用的
                //在finally块中捕获的日志通过日志打印了
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            //异步处理
                            request.getAsyncContextInternal().doInternalDispatch();
                        } else {
                            //调用过滤器链
                            filterChain.doFilter(request.getRequest(),
                                    response.getResponse());
                        }
                    } finally {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            context.getLogger().info(log);
                        }
                    }
                } else {
                    //异步处理
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal().doInternalDispatch();
                    } else {
                         //调用过滤器链
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }

            }
        } catch (ClientAbortException e) {
            。。。。。。省略
        }

        // Release the filter chain (if any) for this request
        if (filterChain != null) {
            //释放链条,将链条引用置空,servlet置空
            filterChain.release();
        }

        // Deallocate the allocated servlet instance
        try {
            if (servlet != null) {
                //servlet计数减一,并把当前servlet设置到servlet池子中
                wrapper.deallocate(servlet);
            }
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.deallocateException",
                             wrapper.getName()), e);
            if (throwable == null) {
                throwable = e;
                exception(request, response, e);
            }
        }

        // If this servlet has been marked permanently unavailable,
        // unload it and release this instance
        try {
            if ((servlet != null) &&
                (wrapper.getAvailable() == Long.MAX_VALUE)) {
                //销毁servlet
                wrapper.unload();
            }
        } catch (Throwable e) {
            ExceptionUtils.handleThrowable(e);
            container.getLogger().error(sm.getString("standardWrapper.unloadException",
                             wrapper.getName()), e);
            if (throwable == null) {
                throwable = e;
                exception(request, response, e);
            }
        }
        long t2=System.currentTimeMillis();

        long time=t2-t1;
        processingTime += time;
        if( time > maxTime) maxTime=time;
        if( time < minTime) minTime=time;

    }

异步处理是servlet3.0新增的,无法就是将操作的方式从同步变成了异步,然后保持长连接即可(我个人理解),所以这里就不进行额外的分析了,我们直接分析过滤链吧

public static ApplicationFilterChain org.apache.catalina.core.ApplicationFilterFactory.createFilterChain(ServletRequest request,
            Wrapper wrapper, Servlet servlet) {

        // If there is no servlet to execute, return null
        if (servlet == null)
            return null;

        // Create and initialize a filter chain object
        ApplicationFilterChain filterChain = null;
        if (request instanceof Request) {
            Request req = (Request) request;
            if (Globals.IS_SECURITY_ENABLED) {
                // Security: Do not recycle
                filterChain = new ApplicationFilterChain();
            } else {
                //从缓存中获取,如果没有就创建一个
                filterChain = (ApplicationFilterChain) req.getFilterChain();
                if (filterChain == null) {
                    filterChain = new ApplicationFilterChain();
                    req.setFilterChain(filterChain);
                }
            }
        } else {
            // Request dispatcher in use
            filterChain = new ApplicationFilterChain();
        }
        //设置servlet
        filterChain.setServlet(servlet);
        //设置是否支持异步
        filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

        // Acquire the filter mappings for this Context
        //父容器
        StandardContext context = (StandardContext) wrapper.getParent();
        //获取过滤器FilterMap,维护这mapping与过滤器的关系
        FilterMap filterMaps[] = context.findFilterMaps();

        // If there are no filter mappings, we are done
        //如果没有过滤器,那啥也不用干了,真爽
        if ((filterMaps == null) || (filterMaps.length == 0))
            return (filterChain);

        // Acquire the information we will need to match filter mappings
        //获取请求分发类型
        DispatcherType dispatcher =
                (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

        String requestPath = null;
        //获取请求路径
        Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
        if (attribute != null){
            requestPath = attribute.toString();
        }
        //获取servlet名字
        String servletName = wrapper.getName();

        // Add the relevant path-mapped filters to this filter chain
        for (int i = 0; i < filterMaps.length; i++) {
            //匹配请求分发类型,我们在配置filter的时候如果没有指定,那么默认是REQUEST类型
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            //匹配url,也分为精确匹配,前缀匹配(也就是后缀通配符为/*的),扩展名匹配
            if (!matchFiltersURL(filterMaps[i], requestPath))
                continue;
            //从context中找到对应的过滤器配置对象
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            //添加
            filterChain.addFilter(filterConfig);
        }

        // Add filters that match on servlet name second
        //通过servlet的名字进行匹配
        for (int i = 0; i < filterMaps.length; i++) {
            //匹配分发类型
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            //匹配servlet的名字,如果过滤器配置是*,那么表示匹配所有
            if (!matchFiltersServlet(filterMaps[i], servletName))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // Return the completed filter chain
        return filterChain;
    }

现在我们已经准备好了所有适用于当前servlet的过滤器,那么我们就来看下这个链条是怎么驱动的。

 void org.apache.catalina.core.ApplicationFilterChain.addFilter(ApplicationFilterConfig filterConfig) {

        // Prevent the same filter being added multiple times
        //如果已经添加了,那么不允许再次添加
        for(ApplicationFilterConfig filter:filters)
            if(filter==filterConfig)
                return;
        //拷贝
        if (n == filters.length) {
            ApplicationFilterConfig[] newFilters =
                new ApplicationFilterConfig[n + INCREMENT];
            System.arraycopy(filters, 0, newFilters, 0, n);
            filters = newFilters;
        }
        //添加到数组后面
        filters[n++] = filterConfig;

    }
    
    
     public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
        //如果开启了JDK的安全管理,那么需要通过这种调用方式获取最高权限,不被安全拦截
        if( Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            try {
                java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedExceptionAction<Void>() {
                        @Override
                        public Void run()
                            throws ServletException, IOException {
                            internalDoFilter(req,res);
                            return null;
                        }
                    }
                );
            } catch( PrivilegedActionException pe) {
                。。。。。。省略
            }
        } else {
            internalDoFilter(request,response);
        }
    }
    
    
    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {

        // Call the next filter if there is one
        if (pos < n) {
            //pos表示当前将要调用的filter的下标
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();
                //如果request要求是异步支持,但是过滤却不支持,那么就设置为不支持异步
                if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                        filterConfig.getFilterDef().getAsyncSupported())) {
                    request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
                }
                //是否开启了JDK的安全管理器
                if( Globals.IS_SECURITY_ENABLED ) {
                    final ServletRequest req = request;
                    final ServletResponse res = response;
                    Principal principal =
                        ((HttpServletRequest) req).getUserPrincipal();

                    Object[] args = new Object[]{req, res, this};
                    //通过安全管理器的方式调用,这种调用方式是为了获取最高权限,防止jdk的安全拦截
                    SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
                } else {
                    //调用过滤器的doFilter方法,驱动链条调用。
                    filter.doFilter(request, response, this);
                }
            } catch (IOException | ServletException | RuntimeException e) {
                throw e;
            } catch (Throwable e) {
                e = ExceptionUtils.unwrapInvocationTargetException(e);
                ExceptionUtils.handleThrowable(e);
                throw new ServletException(sm.getString("filterChain.filter"), e);
            }
            return;
        }

        // We fell off the end of the chain -- call the servlet instance
        try {
            //将request与response设置到当前线程中
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(request);
                lastServicedResponse.set(response);
            }
            //判断是否支持异步请求
            if (request.isAsyncSupported() && !servletSupportsAsync) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                        Boolean.FALSE);
            }
            // Use potentially wrapped request from this point
            if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse) &&
                    Globals.IS_SECURITY_ENABLED ) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal =
                    ((HttpServletRequest) req).getUserPrincipal();
                //安全管理的方式调用,这种调用方式是为了获取最高权限,防止jdk的安全拦截
                Object[] args = new Object[]{req, res};
                SecurityUtil.doAsPrivilege("service",
                                           servlet,
                                           classTypeUsedInService,
                                           args,
                                           principal);
            } else {
                //调用servlet的service方法
                servlet.service(request, response);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.servlet"), e);
        } finally {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(null);
                lastServicedResponse.set(null);
            }
        }
    }

现在我们终于看到了servlet的service方法,我们在实现一个servlet的时候,一般不会覆盖servlet的service方法,那到底是为什么呢?

public void javax.servlet.http.HttpServlet.service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

        HttpServletRequest  request;
        HttpServletResponse response;

        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
    }
    
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        //获取请求方法
        String method = req.getMethod();
        //get
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    ifModifiedSince = -1;
                }
                //比较,查看是否已经过期,如果过期,重新响应
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    //如果没有过期,那么直接返回304
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
        //head
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);
        //post
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
        //put
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
        //delete
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
        //options
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
        //trace
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {
            //不支持的请求方法
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);

            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

好了,到此,tomcat的分析就结束了。至于session的管理,以后有时间在来写个番外吧,哈哈,我这么懒,谁知道什么时候呢?