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


相关文章
|
6月前
|
Java Spring 容器
[JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别
[JavaWeb]——过滤器filter与拦截器Interceptor的使用、执行过程、区别
104 0
|
6月前
|
Java 应用服务中间件 数据安全/隐私保护
面试官:过滤器Filter和拦截器Interceptors有什么区别?
面试官:过滤器Filter和拦截器Interceptors有什么区别?
67 0
|
3月前
|
安全 Java 数据库连接
|
5月前
|
监控 前端开发 Java
Filter和Interceptor都是用于在请求处理的不同阶段进行处理的组件
Filter和Interceptor都是用于在请求处理的不同阶段进行处理的组件
28 0
|
6月前
行为型 责任链模式(过滤器模式)
行为型 责任链模式(过滤器模式)
51 1
|
Java 网络架构 Spring
过滤器执行顺序
过滤器执行顺序
111 0
过滤器执行顺序
Filter过滤器概念及生命周期
Filter过滤器概念及生命周期
155 0
|
Java 容器
sprigboot中过滤器执行顺序源码解读
本文主要是搞清楚对于同一请求在springboot项目中自定义的filter和jar包中的filter的执行顺序是如何指定的。
sprigboot中过滤器执行顺序源码解读
过滤器链模式PK匿名方法实现,哪个更优雅?
过滤器链模式PK匿名方法实现,哪个更优雅?
105 0
过滤器链模式PK匿名方法实现,哪个更优雅?