【记录版】Servlet中Filter的链式执行流程
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框架中完美展现,具体内容戳这里。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!