Spring--拦截器与过滤器

一、简介

Spring 的拦截器(HandlerInterceptor)和过滤器(Filter)都是用于请求处理的组件,但拦截器更适合于Spring MVC的应用场景,提供了更丰富的Spring特性支持;而过滤器则更通用,适用于需要在Web容器层面上进行处理的场景。

二、拦截器与过滤器的区别

总结来说,拦截器和过滤器都可以用来对请求进行预处理和后处理,以下是他们在设计目的、工作机制和使用场景上的不同点:

  1. 设计目的:
    • 拦截器:主要用于处理Spring MVC框架内部的请求处理流程,例如在控制器方法执行前后添加业务逻辑。
    • 过滤器:主要用于在Web容器层面上对请求和响应进行预处理和后处理,可以处理所有类型的请求,不仅限于Spring MVC。
  2. 工作机制:
    • 拦截器:基于Spring的代理机制,拦截器可以访问Spring的IoC容器,因此可以访问到其他的bean。
    • 过滤器:基于Servlet规范的过滤器链,每个过滤器都是独立工作的,不依赖于Spring的容器。
  3. 使用场景:
    • 拦截器:
      • 预处理请求,例如检查用户权限、记录日志等。
      • 处理请求,例如修改模型数据。
      • 后处理响应,例如添加响应头、处理异常等。
    • 过滤器:
      • 跨域请求处理(CORS)。
      • 请求数据的编码解码。
      • 请求和响应的压缩和解压。
      • 安全性控制,例如防止SQL注入、XSS攻击等。
      • 请求的性能统计。
  4. 生命周期:
    • 拦截器:在Spring MVC的DispatcherServlet中处理请求时被调用。
    • 过滤器:在Servlet容器处理请求之前或之后被调用,这意味着在Spring MVC的上下文中,过滤器可能先于拦截器被调用。
  5. 性能:
    • 拦截器:因为依赖于Spring的容器,所以可能比过滤器有更多的开销。
    • 过滤器:作为Servlet规范的一部分,通常性能开销较小。
  6. 配置:
    • 拦截器:通过Spring的配置文件或者Java配置类来定义和注册。
    • 过滤器:通过web.xml或者使用Servlet 3.0的注解来配置。

三、拦截器

拦截器是一种基于Java的编程机制,用于拦截和处理HTTP请求,其实现原理主要基于Java的动态代理机制和AOP(面向切面编程)概念,并结合了责任链和适配器设计模式。它允许开发者在请求到达控制器之前或响应被发送回客户端之后,插入自定义的业务逻辑。

3.1 拦截器工作原理
  1. 拦截器接口:Spring MVC提供了一个HandlerInterceptor接口,该接口包含了三个回调方法:preHandle、postHandle和afterCompletion。开发者需要创建一个类并实现这个接口,以便在请求处理的不同阶段执行自定义逻辑。
  2. 拦截器链:当Spring MVC应用启动时,或者通过配置动态添加拦截器时,Spring会构建一个拦截器链。这个链由多个拦截器组成,每个拦截器按照一定顺序链接在一起。当一个请求到达Spring MVC时,它会依次通过这些拦截器,每个拦截器都有机会对请求进行处理。
  3. 适配器模式:为了让拦截器能够以统一的方式被调用,Spring MVC使用了适配器模式。HandlerExecutionChain类就是一个适配器,它包装了一个或多个拦截器以及一个处理器(Controller)。
  4. 动态代理:Spring MVC使用动态代理技术来创建拦截器的代理对象。当请求到达时,实际上是通过这个代理对象来调用preHandle、postHandle和afterCompletion方法的。如果拦截器实现了HandlerInterceptor接口,那么代理对象会调用这些方法;如果没有,代理对象会直接调用处理器的方法。
  5. 预处理(preHandle):在请求处理器被调用之前,每个拦截器都会调用preHandle方法。如果某个拦截器的preHandle方法返回false,那么请求处理将停止,不会继续传递给链中的后续拦截器和处理器。
  6. 请求处理器调用:如果所有拦截器的preHandle方法都返回true,则请求会被传递给请求处理器执行。
  7. 后置处理(postHandle):在请求处理器执行完成后,每个拦截器会按照逆序调用postHandle方法。这个方法允许在视图渲染之前对模型数据进行修改。
  8. 清理(afterCompletion):在整个请求处理完毕后,无论是否发生异常,每个拦截器都会调用afterCompletion方法。这个方法通常用于资源清理和日志记录等操作。
  9. DispatcherServlet处理:DispatcherServlet作为前端控制器,负责协调拦截器链和请求处理器之间的交互,确保请求正确地经过拦截器链,并最终由合适的处理器处理。
3.2 拦截器使用步骤

在Spring MVC中,使用拦截器涉及到以下几个步骤:

  1. 实现HandlerInterceptor接口:创建一个类并实现HandlerInterceptor接口,覆盖其中的preHandle、postHandle和afterCompletion方法。
bash 复制代码
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在控制器处理请求之前执行的逻辑
        // 如果返回false,则后续的拦截器和处理器都不会被执行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在控制器处理请求之后、视图渲染之前执行的逻辑
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在整个请求处理完成之后执行的逻辑
    }
}
  1. 配置拦截器:在Spring配置文件中注册拦截器。可以通过XML配置或Java配置来实现。
bash 复制代码
## 在spring-mvc.xml配置示例:
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/> <!-- 匹配所有路径 -->
        <mvc:exclude-mapping path="/login"/> <!-- 排除特定路径 -->
        <bean class="com.example.MyInterceptor"/> <!-- 拦截器的Bean类 -->
    </mvc:interceptor>
</mvc:interceptors>
bash 复制代码
## Java配置示例:
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/login");
    }
}
  1. 使用拦截器:配置完成后,当HTTP请求到达Spring MVC时,拦截器会自动工作。拦截器会根据配置的路径模式拦截请求,并执行相应的拦截逻辑。

以上步骤完成后,MyInterceptor类中实现的拦截逻辑就会按照配置的规则对请求进行拦截。通过这种方式,可以在不修改现有控制器代码的情况下,统一处理请求前、后以及处理完成后的逻辑。

四、过滤器

在Spring框架中,过滤器是Java Servlet API的一部分,它主要用于在请求到达Servlet之前和响应返回客户端之前对请求和响应进行预处理和后处理。过滤器是通过实现javax.servlet.Filter接口来创建的,并且必须在web.xml中配置,或者在基于Java的配置中声明。

4.1 过滤器工作原理
  1. 定义过滤器:开发者首先定义一个类,实现javax.servlet.Filter接口或者继承org.springframework.web.filter.GenericFilterBean。后者提供了Spring的集成特性,如依赖注入。
  2. 注册过滤器:在Spring配置中,可以通过XML配置或者Java配置来注册过滤器。使用Java配置时,可以使用@Bean注解创建过滤器的Bean,并使用FilterRegistrationBean来注册。
  3. 配置过滤器顺序:在注册过滤器时,需要指定过滤器的URL模式,以及它在过滤器链中的顺序。过滤器链是按照注册顺序来处理请求的。
  4. 初始化:当Web应用启动或者过滤器被首次请求时,Spring容器会创建过滤器的实例,并调用其init方法进行初始化。
  5. 拦截请求:当请求匹配过滤器的URL模式时,Spring容器会创建一个FilterChainProxy对象,并调用其doFilter方法。FilterChainProxy是Spring提供的一个代理类,它封装了真实的过滤器链。
  6. 执行过滤器逻辑:FilterChainProxy会遍历注册的过滤器列表,并按顺序调用每个过滤器的doFilter方法。在每个doFilter方法中,过滤器可以对ServletRequest和ServletResponse对象进行检查和修改。
  7. 调用下一个过滤器:在doFilter方法中,过滤器可以选择调用FilterChain对象的doFilter方法,将请求传递给下一个过滤器;如果当前过滤器是链中的最后一个过滤器,则请求会传递给Spring MVC的DispatcherServlet。
  8. 处理响应:在DispatcherServlet处理完请求并生成响应后,响应会沿着过滤器链逆向返回。每个过滤器都有机会对响应进行最后的修改。
  9. 销毁:当Web应用停止或者过滤器不再需要时,Spring容器会调用过滤器的destroy方法,以便释放资源。
4.2 过滤器使用步骤

在Spring Boot中使用过滤器通常涉及以下步骤:

  1. 创建过滤器类:实现javax.servlet.Filter接口或继承org.springframework.web.filter.GenericFilterBean。并覆盖init、doFilter和destroy三个方法。
bash 复制代码
public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 过滤器初始化代码
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 在请求到达目标资源之前的处理逻辑
        chain.doFilter(request, response);
        // 在响应返回给客户端之后的处理逻辑
    }

    @Override
    public void destroy() {
        // 过滤器销毁时的清理代码
    }
}
  1. 注册过滤器:在Spring配置文件中注册过滤器,或者使用Java配置。
bash 复制代码
## 在web.xml配置文件注册:
<filter>
    <filter-name>exampleFilter</filter-name>
    <filter-class>com.example.filter.ExampleFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>exampleFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
bash 复制代码
## 使用Java配置注册:
@Configuration
public class WebConfig {
    @Bean
    public FilterRegistrationBean<ExampleFilter> exampleFilter() {
        FilterRegistrationBean<ExampleFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new ExampleFilter());
        registrationBean.addUrlPatterns("/*"); // 设置过滤器适用的URL模式
        return registrationBean;
    }
}
  1. 设置过滤器顺序:可以通过setOrder方法为过滤器设置排序权重,数字越小优先级越高。
bash 复制代码
registrationBean.setOrder(1); // 设置过滤器顺序
  1. 启动应用程序:部署并启动应用程序。Spring容器会自动检测到过滤器并进行注册,无需手动在web.xml中配置。
  2. 测试过滤器:通过发送HTTP请求来测试过滤器是否按预期工作。

以上步骤完成后,过滤器就会按照指定的URL模式介入请求处理流程,执行doFilter方法中定义的业务逻辑。如果需要,还可以在init方法中进行初始化操作,或者在destroy方法中进行清理操作。

相关推荐
是小崔啊7 分钟前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
黄公子学安全16 分钟前
Java的基础概念(一)
java·开发语言·python
liwulin050617 分钟前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr
jackiendsc22 分钟前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
qxlxi22 分钟前
【Spring事务】深入浅出Spring事务从原理到源码
spring
Yuan_o_22 分钟前
Linux 基本使用和程序部署
java·linux·运维·服务器·数据库·后端
Oneforlove_twoforjob26 分钟前
【Java基础面试题027】Java的StringBuilder是怎么实现的?
java·开发语言
程序员一诺1 小时前
【Python使用】嘿马python高级进阶全体系教程第10篇:静态Web服务器-返回固定页面数据,1. 开发自己的静态Web服务器【附代码文档】
后端·python
数据小小爬虫1 小时前
利用Java爬虫获取苏宁易购商品详情
java·开发语言·爬虫
小汤猿人类1 小时前
nacos-服务发现注册
java·开发语言·服务发现