Fork me on GitHub
11 October 2019

环境:

  • Tomcat 9.0.17

Filter通过FilterChain 调用链调用下一个”filter”,应用可在”filter”的public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException方法中调用”filterChain”的相关方法来传递请求到下一个”filter”中。

public interface FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}

Filter 调用过程如下图所示,发起请求时ApplicationFilterChain负责处理FilterServlet相关逻辑。

StandardWrapperValveStandardWrapperValveApplicationFilterFactoryApplicationFilterFactoryApplicationFilterChainApplicationFilterChainFilterFilterServletServletinvoke(request, response)createFilterChain(request, wrapper, servlet)doFilterdoFilterdoFilter(调用全部 filter 后)service

ApplicationFilterChaininternalDoFilter方法实现上述逻辑。pos记录当前”filter”序号,每执行一次filter.doFilterpos加1,直到执行完全部的”filter”,然后执行servlet.service相关逻辑。也就是说应用可在执行filterChian.doFilter完后添加自定义逻辑,即可保证在servlet.service之后执行,从而达到修改response等对象的目的。

// 调用 filter 和 servlet
// (省略无关代码, 完整代码查看 org.apache.catalina.core.ApplicationFilterChain)
private void internalDoFilter(ServletRequest request,
                                ServletResponse response)
    throws IOException, ServletException {

    // 判断是否需要调用下一个 filter
    // pos 为当前执行到的 filter 序号; n 为 filter 数量
    if (pos < n) {
        // 取出对应序号的 filter,然后加 1
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();
            ...
            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};
                // 调用 filter.doFilter
                SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
            } else {
                // 调用 filter.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;
    }

    try {
        ...
        if ((request instanceof HttpServletRequest) &&
                (response instanceof HttpServletResponse) &&
                Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            Principal principal =
                ((HttpServletRequest) req).getUserPrincipal();
            Object[] args = new Object[]{req, res};
            // 调用 servlet.service
            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);
        }
    }
}