多个Filter的执行顺序 | 职责链模式应用

简介: 多个Filter的执行顺序 | 职责链模式应用

前言

 Filter(过滤器) 是 Java Servlet 规范中定义的一种组件,用于在请求到达 Servlet 之前或响应返回给客户端之前对请求和响应进行处理。Filter 的主要作用是拦截、修改或处理传入的请求和传出的响应。


 tomcat作为web容器,提供了对 Filter 的支持。Tomcat 开启了Filter 的生命周期,当请求到达 Tomcat 时,Tomcat 将根据配置的 Filter 映射将请求传递给相应的 Filter。


 Filter 可以设置多个,并且按照一定顺序依次执行,这是因为使用了设计模式中的职责链模式。

一、多个Filter的执行顺序

1. 配置web.xml方式注册Filter

  自定义过滤器:

public class FilterOne implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器1执行——————————————————————————————————————");
        chain.doFilter(request,response);
    }
}
public class FilterTwo implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器2执行——————————————————————————————————————");
        chain.doFilter(request,response);
    }
}
public class FilterThree implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器3执行——————————————————————————————————————");
        chain.doFilter(request,response);
    }
}

  配置 web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
  <!--注册SpringMVC的前端控制器——DispatcherServlet-->
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--关联配置文件-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <!--启动级别1-->
    <load-on-startup>1</load-on-startup>
  </servlet>
  <!--/ 匹配所有请求,不包括jsp-->
  <!--/* 匹配所有请求,包括jsp-->
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <!--配置过滤器FilterOne、FilterTwo、FilterThree-->
  <filter>
    <filter-name>FilterThree</filter-name>
    <filter-class>com.config.FilterThree</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FilterThree</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
    <filter-name>FilterOne</filter-name>
    <filter-class>com.config.FilterOne</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FilterOne</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <filter>
    <filter-name>FilterTwo</filter-name>
    <filter-class>com.config.FilterTwo</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>FilterTwo</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

结论:

  进入调试模式,可以看到过滤器统一放在一个容器中,顺序就是web.xml中从上到下的设置顺序。

  最后出来的打印执行顺序如下:按照解析web.xml的顺序添加的过滤器,并按照添加顺序执行的。

2. 注解方式注册Filter

  自定义过滤器:

@WebFilter(filterName = "FilterOne", urlPatterns = {"/*"})
public class FilterOne implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器1执行——————————————————————————————————————");
        chain.doFilter(request,response);
    }
}
@WebFilter(filterName = "FilterThree", urlPatterns = {"/*"})
public class FilterThree implements Filter{
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器3执行——————————————————————————————————————");
        chain.doFilter(request,response);
    }
}
@WebFilter(filterName = "FilterTwo", urlPatterns = {"/*"})
public class FilterTwo implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器2执行——————————————————————————————————————");
        chain.doFilter(request,response);
    }
}

结论:

  最后出来的打印执行顺序如下:



   根据类名的字母顺序排序,也就是说按字母顺序添加的过滤器,并且也按添加顺序执行的。

二、职责链模式的应用

1. 回顾职责链模式

 先来回顾职责链模式的特点:职责链模式——向上级申请加薪

 职责链模式特点如下:


分离发送者和接收者:将发送者和接收者解耦,发送者只需要将请求发送给职责链的起始节点,而不需要知道具体的接收者。接收者也不需要知道请求的发送者是谁。


多个处理节点处理请求:请求会在职责链上的多个处理节点中依次传递,每个节点都有机会处理请求。这样可以将复杂的处理逻辑分解成多个独立的节点。


请求的处理可以终止:每个处理节点都可以决定是否继续传递请求给下一个节点或终止处理。这样可以灵活地控制请求的处理流程。

2. Filter职责链模式的应用

  所有过滤器都实现了doFilter方法,但是没有设置下级链的方法。

 Tomcat包中的ApplicationFilterFactory类中有个createFilterChain()方法,它的主要作用是将一组 Filters 以特定的顺序组合成一个 FilterChain,自动设置好了每一链的下级链。


 FilterChain 将被用于处理传入的请求,按照预定的顺序调用相应的 Filters 和最终的 Servlet(请求的方法)。


  例如:

 createFilterChain()方法大致的工作内容:


根据web.xml配置的 Filter 映射和顺序创建一个 FilterChain 对象。

将 FilterChain 初始化为包含所有配置的Filters,并按照预定的顺序进行排序。

返回创建的FilterChain 对象。

总结

 Filter 使用职责链模式(Chain of Responsibility Pattern)的优势:


分离责任:将处理逻辑分散到多个 Filter 中,每个 Filter 只负责特定的处理任务。这样可以将复杂的处理逻辑分解为多个独立的模块,每个模块只关注自己的责任,实现了职责的分离。


可扩展性:支持添加、移除和调整处理节点。可以根据需要增加新的 Filter,也可以移除或替换现有的 Filter,而不需要修改已有的代码。这使得系统具有良好的扩展性,可以灵活地应对变化的需求。


可重用性:每个 Filter 负责独立的处理任务,可以被多个不同的请求或系统复用。这样可以避免重复编写相同的处理逻辑,提高代码的可重用性和可维护性。


灵活性:允许根据实际需求动态调整处理流程。可以根据请求的类型、状态或其他条件来动态选择、排列和调整 Filter 的顺序,从而灵活地定制处理流程,以满足不同的业务需求。


 通过使用职责链模式,Filter 可以形成一个灵活、可扩展和可定制的处理链,每个 Filter 只负责特定的处理任务,处理逻辑分散到不同的节点中,实现了解耦合和职责的分离。这样可以提高代码的可维护性、可重用性和灵活性,同时使系统能够适应变化的需求。


相关文章
|
Java Spring 容器
解决Spring的UnsatisfiedDependencyException异常的方法
在Spring开发中,UnsatisfiedDependencyException异常意味着依赖注入失败,影响应用稳定性。该异常由Spring容器在无法满足bean依赖时抛出,常见原因包括bean定义错误、循环依赖、多个候选bean等。解决方法包括:检查bean定义和注入的正确性、解决循环依赖、确认依赖包的兼容性、使用@Qualifier或@Primary注解。通过日志、调试工具和异常对比来定位问题。持续学习Spring框架有助于更好地解决此类异常。
11274 11
|
固态存储 安全 Java
Maven settings.xml 最全配置详解:从入门到精通
本文深入讲解了 Maven settings.xml 的完整配置项,包含本地仓库路径、镜像源配置、代理设置、认证信息、Profile 多环境切换等核心内容。通过 10 个实战案例展示了企业级配置最佳实践,提供可直接使用的配置文件模板。掌握这些技能,你将能够轻松应对团队标准化、私服集成、多环境部署等场景。适合 Java 开发者、DevOps 工程师阅读。
Maven settings.xml 最全配置详解:从入门到精通
|
8月前
|
Oracle Java 关系型数据库
JDK 8安装教程 Windows版详细步骤+环境变量配置(含java/javac/java -version验证)
JDK是Oracle开发的Java开发工具包,含JVM、类库、编译器等,支持Java全平台。本文详解JDK 8下载、安装(含管理员运行)、环境变量配置(JAVA_HOME/CLASSPATH/Path)及cmd验证步骤,助你快速完成本地开发环境搭建。(239字)
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
3458 1
|
7月前
|
缓存 JavaScript 安全
Node.js 和 NPM 更新到最新版本的完整指南
本文提供Node.js与NPM安全、高效更新的完整指南:涵盖NVM、官方安装包及各系统包管理器(Homebrew、NodeSource、nvm-windows)操作步骤,强调更新新功能、修复漏洞、提升兼容性,并提醒备份、本地测试等最佳实践。(239字)
13252 3
|
安全 Java Spring
Spring Boot 过滤器(Filter)详解
本文详解Spring Boot中过滤器的原理与实践,涵盖Filter接口、执行流程、@Component与FilterRegistrationBean两种实现方式、执行顺序控制及典型应用场景如日志记录、权限验证。对比拦截器,突出其在Servlet容器层的通用性与灵活性,助力构建高效稳定的Web应用。
6312 1
|
开发工具 git
解决git push时的错误提示:“error: src refspec master does not match any”
8 .如果确认以上都无误但依然出现该提示,则可能需要重新设置跟踪上游(upstream),通过如下命令:
5396 8
|
Java 开发者 数据格式
【Java笔记+踩坑】SpringBoot基础4——原理篇
bean的8种加载方式,自动配置原理、自定义starter开发、SpringBoot程序启动流程解析
【Java笔记+踩坑】SpringBoot基础4——原理篇
|
安全 Java API
深入探索 org.springframework.http.server.reactive.ServerHttpRequest:Reactive世界中的HTTP请求处理
深入探索 org.springframework.http.server.reactive.ServerHttpRequest:Reactive世界中的HTTP请求处理
964 0

热门文章

最新文章