OncePerRequestFilter-源码解析

在spring中,filter都默认继承OncePerRequestFilter,但为何要这样呢?
OncePerRequestFilter顾名思义,他可以确保在一次请求只经过一次filter,而不须要重复执行。java

/** * 过滤器基类,旨在确保每一个请求调度在任何servlet容器上执行一次执行。 * 它提供了一个带有HttpServletRequest和HttpServletResponse参数的{@link #doFilterInternal}方法。 */
public abstract class OncePerRequestFilter extends GenericFilterBean {
    //附加到“已过滤”请求属性的过滤器名称的后缀。
    public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED"; 

    //这个doFilter实现存储“已通过滤”的请求属性,若是该属性已经存在,则不进行再次过滤。
    //@see #getAlreadyFilteredAttributeName
    @Override
    public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
            throw new ServletException("OncePerRequestFilter just supports HTTP requests");
        }
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
        boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;

        if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {

            // 继续而不调用此过滤器...
            filterChain.doFilter(request, response);
        }
        else {
            // 调用这个过滤器…
            request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);
            try {
                doFilterInternal(httpRequest, httpResponse, filterChain);
            }
            finally {
                // 删除此请求的“已过滤”请求属性。
                request.removeAttribute(alreadyFilteredAttributeName);
            }
        }
    }

    /** * 返回代表请求已被过滤的请求属性的名称。 */
    protected String getAlreadyFilteredAttributeName() {
        // 若是没有可用的过滤器名,则为{@code null}
        String name = getFilterName();
        if (name == null) {
            name = getClass().getName();
        }
        return name + ALREADY_FILTERED_SUFFIX;
    }

    private boolean skipDispatch(HttpServletRequest request) {
        if (isAsyncDispatch(request) && shouldNotFilterAsyncDispatch()) {
            return true;
        }
        if (request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE) != null && shouldNotFilterErrorDispatch(){
            return true;
        }
        return false;
    }

    /** * 在Servlet 3.0中引入的调度器类型{@code javax.servlet.DispatcherType.ASYNC}意味着一个过滤器能够在一个请求过程当中在多个线 * 程中被调用。 若是过滤器当前在异步分派中执行,则此方法返回{true}。 */
    protected boolean isAsyncDispatch(HttpServletRequest request) {
        return WebAsyncUtils.getAsyncManager(request).hasConcurrentResult();
    }

    /** * 请求处理是否处于异步模式,意味着退出当前线程后不会提交响应。 */
    protected boolean isAsyncStarted(HttpServletRequest request) {
        return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
    }

    /** * 能够在子类中覆盖自定义过滤控件,返回{true}以免过滤给定的请求。 默认实现老是返回{@code false}。 */
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        return false;
    }

    protected boolean shouldNotFilterAsyncDispatch() {
        return true;
    }

    protected boolean shouldNotFilterErrorDispatch() {
        return true;
    }

    /** * 与{@code doFilter}相同的合同,但保证在单个请求线程中每一个请求只调用一次。 * / protected abstract void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException; }

参考网站: https://blog.csdn.net/ktlifeng/article/details/50630934web

// GenericFilterBean.class

    //使这个过滤器的名称对子类可用。相似于GenericServlet的{@code getServletName()}。<p>默认使用FilterConfig的过滤器名称。
    //若是在Spring应用程序上下文中初始化为bean,那么它将返回到bean工厂中定义的bean名称。
    @Nullable
    protected String getFilterName() {
        return (this.filterConfig != null ? this.filterConfig.getFilterName() : this.beanName);
    }