Tomcat处理请求

Tomcat处理请求

    • StandardEngineValve
    • StandardHostValve
    • StandardContextValve
    • StandardWrapperValve

Tomcat启动时会创建一个线程池和连接器,开启端口监听网络请求,然后解析网络请求并且封装到Request、Response类中,由CoyoteAdapter的service(org.apache.coyote.Request req, org.apache.coyote.Response res)方法开始交由Container容器处理,最后将容器处理完的响应数据交由连接器发送给请求调用方。

connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);V

这里有一个概念:每一个容器Container都有一个pipeline负责对应若干Valve的维护,Valve就是负责相应容器的逻辑处理器。每一个容器组件都有个默认的Valve,被设置为Basic,比如StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve,用于该组件最后调用下级组件。在相应组件的构造函数内创建:

    /**
     * Create a new StandardEngine component with the default basic Valve.
     */
    public StandardEngine() {

        super();
        //在这里设置了,其余几个组件也一样
        pipeline.setBasic(new StandardEngineValve());
        /* Set the jmvRoute using the system property jvmRoute */
        try {
            setJvmRoute(System.getProperty("jvmRoute"));
        } catch(Exception ex) {
            log.warn(sm.getString("standardEngine.jvmRouteFail"));
        }
        // By default, the engine will hold the reloading thread
        backgroundProcessorDelay = 10;
    }

在Pipeline里有两个概念,一个是Basic,指定最基本的处理器,其最终都会执行getPipeline().getFirst().invoke(request, response)调用下级容器的Valve;另一个是First,默认情况下是空的,但是可以通过addValve(Valve valve)方法添加,代码如下:

public void addValve(Valve valve) {
		......
        // Add this Valve to the set associated with this Pipeline
        if (first == null) {
            first = valve;
            valve.setNext(basic);
        } else {
            Valve current = first;
            while (current != null) {
                if (current.getNext() == basic) {
                    current.setNext(valve);
                    valve.setNext(basic);
                    break;
                }
                current = current.getNext();
            }
        }

        container.fireContainerEvent(Container.ADD_VALVE_EVENT, valve);
    }

可以看到每一个调用addValve添加的Valve都会加入到Valve的单向链表中,最后一个Basic Valve之前。
附上一个各个Pipeline的流程图:
Tomcat处理请求_第1张图片

StandardEngineValve

Tomcat处理请求_第2张图片

StandardHostValve

125   if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest()))	创建请求HttpServletRequest,并执行ServletRequestListener监听器的requestInitialized(ServletRequestEvent sre)方法

#StandardContext

//创建RequestFacade implements HttpServletRequest,(interface HttpServletRequest extends ServletRequest)
public HttpServletRequest getRequest() {
        if (facade == null) {
            facade = new RequestFacade(this);
        }
        if (applicationRequest == null) {
            applicationRequest = facade;
        }
        return applicationRequest;
    }

Tomcat处理请求_第3张图片

139		context.getPipeline().getFirst().invoke(request, response);	执行AuthenticatorBase的认证方法,最终执行StandardContextValve的invoke方法
//执行StandardContext中注册了ServletRequestListener监听器的requestDestroyed销毁请求的方法。
181		context.fireRequestDestroyEvent(request.getRequest());	

Tomcat处理请求_第4张图片

StandardContextValve

Tomcat处理请求_第5张图片

StandardWrapperValve

135		servlet = wrapper.allocate();	如果servlet没有初始化,就执行初始化

Tomcat处理请求_第6张图片
在Tomcat的启动阶段就会将那些loadOnStartup值大于等于0的Servlet初始化,然而如果为负数的那些Servlet就会在对应生效的请求中执行初始化。
#StandardWrapper
Tomcat处理请求_第7张图片

//this:StandardWrapper
StandardWrapperFacade facade = new StandardWrapperFacade(this);
servlet.init(facade);

或者是通过 #StandardWrapper 761 instance = loadServlet(); 创建Servlet对象,处理@MultipartConfig注解并初始化Servlet。

// 173	为请求创建FilterChain
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

#ApplicationFilterFactory

public static ApplicationFilterChain createFilterChain(ServletRequest request,
            Wrapper wrapper, Servlet servlet) {

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

        // 创建过滤器链FilterChain
        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());

        // 从StandardContext中获取filter集合
        StandardContext context = (StandardContext) wrapper.getParent();
        FilterMap filterMaps[] = context.findFilterMaps();

        // 如果没有找到filter注册那么FilterChain中就不需要设置Filter了,直接返回。
        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();
        }

        String servletName = wrapper.getName();

        // Add the relevant path-mapped filters to this filter chain
        for (int i = 0; i < filterMaps.length; i++) {
        	//匹配请求的调度方式FORWARD、INCLUDE、REQUEST、ERROR、ASYNC,默认情况下是REQUEST
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            //匹配url是否拦截
            if (!matchFiltersURL(filterMaps[i], requestPath))
                continue;
            //从StandardContext中获取该Filter
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            //将该Filter加入过滤器链
            filterChain.addFilter(filterConfig);
        }

        // Add filters that match on servlet name second
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            //根据Filter配置的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;
    }

匹配请求的调度方式FORWARD、INCLUDE、REQUEST、ERROR、ASYNC,默认情况下是REQUEST:
Tomcat处理请求_第8张图片
匹配url是否拦截:
Tomcat处理请求_第9张图片
具体的匹配规则,代码如下:

private static boolean matchFiltersURL(String testPath, String requestPath) {

        if (testPath == null)
            return false;

        // Case 1 - Exact Match
        if (testPath.equals(requestPath))
            return true;

        // Case 2 - Path Match ("/.../*")
        if (testPath.equals("/*"))
            return true;
        if (testPath.endsWith("/*")) {
            if (testPath.regionMatches(0, requestPath, 0,
                                       testPath.length() - 2)) {
                if (requestPath.length() == (testPath.length() - 2)) {
                    return true;
                } else if ('/' == requestPath.charAt(testPath.length() - 2)) {
                    return true;
                }
            }
            return false;
        }

        // Case 3 - Extension Match
        if (testPath.startsWith("*.")) {
            int slash = requestPath.lastIndexOf('/');
            int period = requestPath.lastIndexOf('.');
            if ((slash >= 0) && (period > slash)
                && (period != requestPath.length() - 1)
                && ((requestPath.length() - period)
                    == (testPath.length() - 1))) {
                return testPath.regionMatches(2, requestPath, period + 1,
                                               testPath.length() - 2);
            }
        }

        // Case 4 - "Default" Match
        return false; // NOTE - Not relevant for selecting filters
    }

根据Filter配置的Servlet过滤:
Tomcat处理请求_第10张图片
总的来说,请求的调度优先级最高必须满足,其次先匹配URL,如果满足就直接加入FilterChain,其次在匹配ServletName,URL和Servlet都可以设置是否全部满足和单个满足。如果一个Filter这两者都满足,最后在过滤器链的添加中会先判断加入的Filter是否存在,不会重复添加。

201		filterChain.doFilter(request.getRequest(), response.getResponse());	执行doFilter方法进行过滤器链的工作

#ApplicationFilterChain

@Override
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
        ......
            internalDoFilter(request,response);
        }
    }

最后调用ApplicationFilterChain # internalDoFilter(ServletRequest request,ServletResponse response)方法(主要逻辑如下):

    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {

        //n表示此过滤器链中的filter个数;
        //pos表示当前执行到的过滤器的下标,从0开始
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();
					......
                    filter.doFilter(request, response, this);
            } catch (){
            ......
            }
            return;
        }

        //当此过滤器链中所有的过滤器都执行完了,则调用下面的Servlet处理器
        ......
       servlet.service(request, response);
       ......

可以看到过滤器链是通过类似递归的责任链模式过滤请求和响应的。当然我们自定义的Filter中必须执行FilterChain#doFilter(ServletRequest servletRequest, ServletResponse servletResponse)方法。例如:

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }

请求属性监听ServletRequestAttributeListener的调用逻辑都在org.apache.catalina.connector.Request类中,和ServletContext,ServletRequest的监听类似。

261	filterChain.release();
267	wrapper.deallocate(servlet);

你可能感兴趣的:(Tomcat)