OncePerRequestFilter-源码解析

129 篇文章 8 订阅
57 篇文章 1 订阅

在spring中,filter都默认继承OncePerRequestFilter,但为什么要这样呢? 
OncePerRequestFilter顾名思义,他能够确保在一次请求只通过一次filter,而不需要重复执行。

/**
* 过滤器基类,旨在确保每个请求调度在任何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;

}

 

    // GenericFilterBean.class

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


--------------------- 
作者:Pazz枫 
来源:CSDN 
原文:https://blog.csdn.net/baidu_36327010/article/details/80538491?utm_source=copy 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值