【记录版】Servlet中Filter的链式执行流程

2023-12-15 03:52:16

Servlet + ApplicationFilterChain + Filter

背景: Web项目中,Filter可以说是离不开的一个组件,也是学习时最先遇到的,可以说无开发者不知、无开发者不晓。Filter有悠久的历史,设计概念也非常符合我们的逻辑思维,常常用作预处理,例如常见的字符集编码、安全控制(spring-security框架底层也是Filter的再封装)、请求体/响应体修改(详见)等等,可以说是项目必备良品。Filter接口很简单,此处不再详述使用方法,后续内容将讲述Filter整体执行的架构设计。

前置说明: 每个请求都有自己的过滤器集,通过跟URI匹配(即控制细致场景不同请求过滤器集不同),且过滤器集有池化缓存【空间换时间】

博客内容精选:
1、Servlet请求体重复读&修改新姿势
2、根据请求获取后端接口详情
3、SpringBoot下Filter自动适配
4、SpringBoot下Filter注册流程
5、Filter链式执行设计解读

核心类ApplicationFilterChain 代码展示【简要篇】

public final class ApplicationFilterChain implements FilterChain {
	// 过滤器链每次扩容增量
    public static final int INCREMENT = 10;
    // 实际存储过滤器封装对象数组,ApplicationFilterConfig配置类包含过滤器名、实例、初始化参数以及ServletContext等核心信息
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
    // 过滤器链每次可重头使用,reuse可置0
    private int pos = 0;
    // 实际过滤器个数,可不等于filters数组长度
    private int n = 0;
    // 存储DispatcherServlet相关类,实现过滤后请求的传递与执行
    private Servlet servlet = null;

    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
            //其他封装逻辑已删除
			
			// 过滤器链执行详情
			this.internalDoFilter(request, response);
    }

    private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
    	// 从【0,n)执行所有过滤器,每次执行Filter的doFilter方法,都会在这里拿到下一个Filter并执行,以此实现链式结构
    	// 如果中间某个Filter执行逻辑报错,或在其doFilter方法执行完成后未使用filterChain对象调用doFilter方法,会发生什么?
        if (this.pos < this.n) {
            ApplicationFilterConfig filterConfig = this.filters[this.pos++];

            try {
                Filter filter = filterConfig.getFilter();
                // 执行我们定义的Filter或系统定义的过滤器,如字符集编码
                filter.doFilter(request, response, this);
				/** 如果此Filter方法执行异常,或未执行filterChain.doFilter方法,有以下两种影响:
				* 1、此Filter后所有Filter以及servlet不再执行
				* 2、此Filter之前已执行的Filter
				* 2.1 异常场景:所有前Filter逐个异常传递,doFilter方法中filterChain.doFilter(...)后的方法体不再执行
				* 2.2 正常场景,依次反向执行doFilter方法中【filterChain.doFilter(...)后】的方法体
				* Filter1.doFilter -> Filter2.doFilter -> Filter3.doFilter
				* Filter1.doFilter <- Filter2.doFilter <- Filter3.doFilter
				*/
			} catch (ServletException | RuntimeException | IOException var15) {
                throw var15;
            } catch (Throwable var16) {
                Throwable e = ExceptionUtils.unwrapInvocationTargetException(var16);
                ExceptionUtils.handleThrowable(e);
                // filterChain.filter异常
                throw new ServletException(sm.getString("filterChain.filter"), e);
            }
        } else {
        	try {
        		// 如果Filter链执行完,此处就会调用servlet的service方法完成我们实际的接口逻辑
        		// @RestController注解也只是封装了控制器到Servlet的过程
               this.servlet.service(request, response);
            } catch (ServletException | RuntimeException | IOException var17) {
            	// 部分异常抛出给上层判断并处理
                throw var17;
            } catch (Throwable var18) {
            	// 全局异常处理
                Throwable e = ExceptionUtils.unwrapInvocationTargetException(var18);
                ExceptionUtils.handleThrowable(e);
                // filterChain.servlet异常
                throw new ServletException(sm.getString("filterChain.servlet"), e);
            } finally {
         		// 资源控制或释放
            }
        }
    }

	// 添加过滤器到链中
    void addFilter(ApplicationFilterConfig filterConfig) {
        ApplicationFilterConfig[] newFilters = this.filters;
        int var3 = newFilters.length;
		// 检查新增过滤器是否已在链中,有则直接退出
        for(int var4 = 0; var4 < var3; ++var4) {
            ApplicationFilterConfig filter = newFilters[var4];
            if (filter == filterConfig) {
                return;
            }
        }
		// 如果过滤器链数组已满,则自动扩容
        if (this.n == this.filters.length) {
            newFilters = new ApplicationFilterConfig[this.n + 10];
            System.arraycopy(this.filters, 0, newFilters, 0, this.n);
            this.filters = newFilters;
        }
		// n++,n从0开始
        this.filters[this.n++] = filterConfig;
    }

	// 过滤器链资源释放,包含变量归零
    void release() {
        for(int i = 0; i < this.n; ++i) {
            this.filters[i] = null;
        }

        this.n = 0;
        this.pos = 0;
        this.servlet = null;
        this.servletSupportsAsync = false;
    }

	// 过滤器链只要将pos重新改为0,即可复用
    void reuse() {
        this.pos = 0;
    }

	// 此处将执行Servlet初始化,必执行DispachterServlet实例
    void setServlet(Servlet servlet) {
        this.servlet = servlet;
    }
}

过滤器链设计理解回顾:

// 过滤器链顶层接口
public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

// 过滤器链管理封装类
public final class ApplicationFilterChain implements FilterChain {
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
	public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
		//循环取filters中的Filter,并执行:
		Filter.doFilter(ServletRequest,ServletResponse,this)
		//注意this对象代表此过滤器链,相当于回形针,Filter中即可用FilterChain.doFilter方法重新回到过滤器链对象中,并根据数组索引值变换依次执行Filter
	}
}

// Filter类接口
public interface Filter {
	// 第三个参数为chain类型,回形针
    void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
}

理解要点:
1、存储为数组结构,通过ApplicationFilterChain对象管理完成数组索引值的自增
2、FilterChain和Filter都有doFilter方法,区别在于Filter的doFilter方法第三个参数为chain对象,可完成引用传递
3、重点理解FilterChain传递,尤其是Filter中doFilter方法中未执行chain的回调后的执行逻辑,曾经有个项目一个doFilter方法几百行,各种if…else…之后就出现坑了
4、其实ApplicationFilterConfig[] filters变量除了可以定义成数组对象,也可以通过链表的形式完成,内部封装自身Filter和下一个Filter变量,只是设计理念和实现方式上的不同。

总结:Filter这种责任链模式实际应用场景较多,而且有多个变种实现方式,有较高的实践及理解意义。除了上述介绍,其实还有其他相关核心概念需要理解,例如池化、Filter注册、优先级控制,且Filter在SpringBoot框架中已完成适配,使用方式也有些许变化,在后续博客中继续记录。Filter的设计及应用,在spring-security框架中完美展现,具体内容戳这里

文章来源:https://blog.csdn.net/src1025/article/details/134906450
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。