doFilter和doFilterInternal

摘录自:https://www.jianshu.com/p/3d9b4cfe1a62

doFilter是整个过滤器最底层的概念Filter接口中的方法
所有过滤器都要实现Filter

复制代码
package javax.servlet;

import java.io.IOException;

public interface Filter {
    void init(FilterConfig var1) throws ServletException;

    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;

    void destroy();
}
复制代码

而doFilterInternal是OncePerRequestFilter 中的一个抽象方法
阅读源码可知:
OncePerRequestFilter.doFilter方法中通过request.getAttribute判断当前过滤器是否已执行
若未执行过,则调用doFilterInternal方法,交由其子类实现

OncePerRequestFilter
顾名思义,它能够确保在一次请求中只通过一次filter,而不会重复执行
是由Spring提供的抽象类

复制代码
package org.springframework.session.web.http;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

abstract class OncePerRequestFilter implements Filter {
    public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
    private String alreadyFilteredAttributeName = this.getClass().getName().concat(".FILTERED");

    OncePerRequestFilter() {
    }

    public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
            HttpServletRequest httpRequest = (HttpServletRequest)request;
            HttpServletResponse httpResponse = (HttpServletResponse)response;
            boolean hasAlreadyFilteredAttribute = request.getAttribute(this.alreadyFilteredAttributeName) != null;
            if (hasAlreadyFilteredAttribute) {
                filterChain.doFilter(request, response);
            } else {
                request.setAttribute(this.alreadyFilteredAttributeName, Boolean.TRUE);

                try {
                    this.doFilterInternal(httpRequest, httpResponse, filterChain);
                } finally {
                    request.removeAttribute(this.alreadyFilteredAttributeName);
                }
            }

        } else {
            throw new ServletException("OncePerRequestFilter just supports HTTP requests");
        }
    }

    protected abstract void doFilterInternal(HttpServletRequest var1, HttpServletResponse var2, FilterChain var3) throws ServletException, IOException;

    public void init(FilterConfig config) {
    }

    public void destroy() {
    }
}
复制代码
常识上都认为,一次请求本来就只filter一次,为什么还要由此特别限定呢?
往往我们的常识和实际的实现并不真的一样,经过一番资料的查阅,此方法是为了兼容不同的web container
也就是说并不是所有的container都入我们期望的只过滤一次,servlet版本不同,执行过程也不同
因此,为了兼容各种不同运行环境和版本,默认filter继承OncePerRequestFilter是一个比较稳妥的选择。
posted @   芬乐  阅读(13357)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
历史上的今天:
2018-08-11 关于Ant脚本
2018-08-11 Maven
2016-08-11 window对象
2016-08-11 关于结构体指针与别名
点击右上角即可分享
微信分享提示