多个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 只负责特定的处理任务,处理逻辑分散到不同的节点中,实现了解耦合和职责的分离。这样可以提高代码的可维护性、可重用性和灵活性,同时使系统能够适应变化的需求。


相关文章
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
存储 Java 文件存储
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录—— logback.xml 配置文件解析
本文解析了 `logback.xml` 配置文件的详细内容,包括日志输出格式、存储路径、控制台输出及日志级别等关键配置。通过定义 `LOG_PATTERN` 和 `FILE_PATH`,设置日志格式与存储路径;利用 `&lt;appender&gt;` 节点配置控制台和文件输出,支持日志滚动策略(如文件大小限制和保存时长);最后通过 `&lt;logger&gt;` 和 `&lt;root&gt;` 定义日志级别与输出方式。此配置适用于精细化管理日志输出,满足不同场景需求。
3045 1
|
安全 Java Spring
Spring Boot 过滤器(Filter)详解
本文详解Spring Boot中过滤器的原理与实践,涵盖Filter接口、执行流程、@Component与FilterRegistrationBean两种实现方式、执行顺序控制及典型应用场景如日志记录、权限验证。对比拦截器,突出其在Servlet容器层的通用性与灵活性,助力构建高效稳定的Web应用。
5799 1
|
11月前
|
JSON 监控 Java
日志与追踪的完美融合:OpenTelemetry MDC 实践指南
日志与追踪的完美融合:OpenTelemetry MDC 实践指南
936 24
|
XML 缓存 算法
SpringBoot2 | SpingBoot FilterRegistrationBean 注册组件 | FilterChain 责任链源码分析(九)
SpringBoot2 | SpingBoot FilterRegistrationBean 注册组件 | FilterChain 责任链源码分析(九)
452 0
|
JSON 安全 Java
Spring Boot中的安全过滤器及使用方法
Spring Boot中的安全过滤器及使用方法
|
监控 前端开发 Java
Java里的过滤器和拦截器是什么原理,如何选择?
Java里的过滤器和拦截器是什么原理,如何选择?
434 0
|
Java Spring 容器
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
Spring boot 自定义ThreadPoolTaskExecutor 线程池并进行异步操作
1365 3
|
存储 Java
SpringBoot中过滤器如何设置执行顺序
SpringBoot中过滤器如何设置执行顺序
1542 0
|
Java 数据库
request.setAttribute()详解
request.setAttribute()详解
1452 1