likes
comments
collection
share

深入探究Spring框架的守门者:精通过滤器与拦截器的策略与实践深入探讨Spring框架中过滤器与拦截器的作用、差异与协

作者站长头像
站长
· 阅读数 47

引言

基于Spring框架的Web应用开发中,保障请求和响应的处理流程既高效又安全是至关重要的。本文将深入探讨Spring中两个关键组件——过滤器(Filter)和拦截器(Interceptor)——的内部工作原理、区别以及它们在现代Web应用中的不同使用场景。通过对这两个组件的深入分析,本文将揭示它们如何作为Spring应用的守门者,对进出的HTTP请求进行精确控制。

正文

在Spring框架中,拦截器(Interceptors)和过滤器(Filters)都可以用来在请求处理流程中的特定点上执行某些任务,但它们在实现和使用场景上有所不同。

拦截器(Interceptors)

拦截器是Spring MVC框架的一部分,它们基于Java的动态代理实现。拦截器可以对处理器(Controller)的请求进行拦截和处理,并且能够访问Spring的上下文(Context),包括所有的Bean和配置。

主要特点

  • 只能用于处理请求(Request)和响应(Response)的Spring MVC操作。
  • 可以访问Spring MVC的执行上下文,包括控制器方法的执行信息。
  • 可以对特定的URL模式进行拦截。
  • 可以访问控制器执行的ModelAndView对象,甚至可以修改它。
  • 提供了多个回调方法:preHandle(请求处理前)、postHandle(请求处理后,渲染视图前)、afterCompletion(请求处理完成后)。

使用场景

  • 在控制器方法执行前后添加逻辑,如日志记录、权限检查、用户认证等。
  • 修改请求或响应对象。
  • 处理异常。
  • 添加或修改视图相关的数据。

自定义拦截器实现

首先,需要创建一个类来实现HandlerInterceptor接口。这个接口包含三个方法:preHandlepostHandleafterCompletion,你可以根据需要重写这些方法。

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

    // 在控制器方法执行之前调用
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 你的逻辑代码
        System.out.println("preHandle is called");
        return true; // 返回true继续流程(如调用下一个拦截器或处理器)
        // 返回false则中断流程
    }

    // 在控制器方法执行之后,解析视图之前调用
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 你的逻辑代码
        System.out.println("postHandle is called");
    }

    // 在整个请求结束后调用,也就是在DispatcherServlet渲染了视图执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 你的逻辑代码
        System.out.println("afterCompletion is called");
    }
}

注册拦截器

接下来,你需要将自定义的拦截器注册到Spring MVC的拦截器链中。这可以通过实现WebMvcConfigurer接口并重写addInterceptors方法来完成。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()) // 注册拦截器
                .addPathPatterns("/**") // 指定拦截的URL模式
                .excludePathPatterns("/login", "/logout"); // 指定不拦截的URL模式
    }
}

在上面的代码中,addPathPatterns方法用于指定哪些路径应该被拦截器拦截,而excludePathPatterns方法用于指定哪些路径不应该被拦截。

完整示例

将上述两个代码片段放在Spring项目中,就可以实现一个简单的拦截器。每当有请求匹配到指定的路径模式时,MyInterceptor中的相应方法就会被调用。

根据实际情况对拦截器的逻辑进行调整。例如,可能希望在preHandle中执行认证和授权检查,在postHandle中添加一些通用模型数据,在afterCompletion中进行资源清理或日志记录等。

过滤器(Filters)

过滤器是Java Servlet API的一部分,它们在Servlet容器级别上对进入的请求和出去的响应进行预处理和后处理。

主要特点

  • 可以用于任何Web资源,如静态资源(HTML、CSS、图片)、JSP、Servlet等。
  • 在Servlet容器中配置,不依赖于Spring应用上下文。
  • 通常用于处理HTTP请求和响应的原始数据。
  • 可以实现javax.servlet.Filter接口的doFilter方法来执行过滤逻辑。
  • 可以创建过滤器链,依次执行多个过滤器。

使用场景

  • 请求日志和响应日志记录。
  • 请求数据的压缩和解压缩。
  • 设置请求字符编码。
  • 安全检查,如跨站点请求伪造(CSRF)防护。
  • 实现HTTP请求的CORS策略。

在Java的Servlet API中,过滤器(Filter)用于在请求到达Servlet之前或响应离开Servlet之后执行一些任务。以下是一个简单的自定义过滤器的示例,包括过滤器的实现以及如何将其注册到Spring Boot应用中。

自定义过滤器实现

首先,你需要创建一个类来实现javax.servlet.Filter接口。这个接口包含一个方法:doFilter,你需要在这个方法中实现你的过滤逻辑。

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*") // 指定过滤器的URL模式
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化代码,只会执行一次
        System.out.println("MyFilter initialized");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 请求到达Servlet之前的代码
        System.out.println("MyFilter doFilter before chain.doFilter");

        // 继续执行其他过滤器,如果没有其他过滤器则执行请求的Servlet
        chain.doFilter(request, response);

        // 响应离开Servlet之后的代码
        System.out.println("MyFilter doFilter after chain.doFilter");
    }

    @Override
    public void destroy() {
        // 销毁时执行的代码,只会执行一次
        System.out.println("MyFilter destroyed");
    }
}

注册过滤器

在Spring Boot应用中,可以使用@WebFilter注解自动注册过滤器,但这要求在Spring Boot的主类或者配置类上添加@ServletComponentScan注解,以便扫描@WebFilter注解并注册过滤器。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan // 启用Servlet组件扫描
public class MySpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

完整示例

将上述两个代码片段放在Spring Boot项目中,就可以实现一个简单的过滤器。每当有请求匹配到指定的路径模式时,MyFilter中的doFilter方法就会被调用。

如果不想使用@ServletComponentScan@WebFilter注解,还可以通过实现FilterRegistrationBean来注册过滤器:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<MyFilter> myFilter() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/*"); // 设置过滤器的URL模式
        return registrationBean;
    }
}

请注意,上述代码仅作为示例,可能需要根据实际情况对过滤器的逻辑进行调整。过滤器通常用于处理一些通用的前置和后置逻辑,例如日志记录、安全检查、请求响应修改等。

区别和选择

  • 作用范围:过滤器可以应用于任何请求,而拦截器只能应用于通过DispatcherServlet映射的请求。
  • 依赖关系:拦截器可以利用Spring容器的功能,如依赖注入等;过滤器通常不依赖Spring容器。
  • 细粒度控制:拦截器提供了更细粒度的控制,可以访问控制器的信息和Spring的上下文。
  • 配置位置:拦截器是在Spring的配置中设置的,而过滤器可以在web.xml中或通过Servlet 3.0的@WebFilter注解配置。

时序图

时序图展示了在Spring框架中处理HTTP请求时,过滤器(Filter)、拦截器(Interceptor)、控制器(Controller)以及异常处理(Exception Handling)和视图渲染(View Rendering)之间的交互。

ClientFilter1FilterNInterceptor1InterceptorNControllerExceptionHandlerViewalt[Controller LogicExecution][SuccessfulExecution]alt[If Exception Occurred][If No Exception and View Exists]HTTP RequestProcess RequestFilter Chain ProceedPre-handlePre-handleThrow ExceptionException HandlingController LogicPost-handlePost-handleError ResponseRender ViewView RenderedFilter Chain ProceedHTTP ResponseClientFilter1FilterNInterceptor1InterceptorNControllerExceptionHandlerView

时序图中,流程如下:

  1. 客户端(Client) 发送一个HTTP请求。
  2. 第一个过滤器(Filter1) 拦截到这个请求,并对其进行预处理,然后将处理过的请求传递给下一个过滤器。
  3. 最后一个过滤器(FilterN) 在过滤器链中的最后一个过滤器接收请求,并将其传递给第一个拦截器。
  4. 第一个拦截器(Interceptor1) 执行preHandle方法,如果返回true,则将请求传递给下一个拦截器。
  5. 最后一个拦截器(InterceptorN) 执行preHandle方法,并将请求传递给控制器。
  6. 控制器(Controller) 执行业务逻辑。如果过程中抛出异常,将转入异常处理。
  7. 异常处理器(ExceptionHandler) 处理异常,并返回控制权给控制器。
  8. 如果控制器执行成功,控制器将控制权返回给最后一个拦截器。
  9. 拦截器(InterceptorN) 执行postHandle方法,然后将控制权返回给第一个拦截器。
  10. 拦截器(Interceptor1) 执行postHandle方法,然后将控制权返回给最后一个过滤器。
  11. 如果异常发生,最后一个过滤器将发送错误响应回客户端。如果没有异常并且存在视图,最后一个过滤器将请求转发给视图进行渲染。
  12. 视图(View) 渲染并返回控制权给最后一个过滤器。
  13. 最后一个过滤器(FilterN) 将控制权返回给第一个过滤器。
  14. 第一个过滤器(Filter1) 将最终的HTTP响应发送回客户端。

总结

选择使用拦截器还是过滤器时,需要考虑具体需求。如果需要在Spring MVC的上下文中处理请求,并且需要访问或修改控制器的信息,那么拦截器可能是更好的选择。如果操作需要在更低的级别上处理所有类型的Web资源,或者应用不是基于Spring MVC的,那么过滤器可能更适合需求。

本文皆为个人原创,请尊重创作,未经许可不得转载。

转载自:https://juejin.cn/post/7419306819284205618
评论
请登录