深入探究Spring框架的守门者:精通过滤器与拦截器的策略与实践深入探讨Spring框架中过滤器与拦截器的作用、差异与协
引言
基于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
接口。这个接口包含三个方法:preHandle
、postHandle
和afterCompletion
,你可以根据需要重写这些方法。
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)之间的交互。
时序图中,流程如下:
- 客户端(Client) 发送一个HTTP请求。
- 第一个过滤器(Filter1) 拦截到这个请求,并对其进行预处理,然后将处理过的请求传递给下一个过滤器。
- 最后一个过滤器(FilterN) 在过滤器链中的最后一个过滤器接收请求,并将其传递给第一个拦截器。
- 第一个拦截器(Interceptor1) 执行
preHandle
方法,如果返回true
,则将请求传递给下一个拦截器。 - 最后一个拦截器(InterceptorN) 执行
preHandle
方法,并将请求传递给控制器。 - 控制器(Controller) 执行业务逻辑。如果过程中抛出异常,将转入异常处理。
- 异常处理器(ExceptionHandler) 处理异常,并返回控制权给控制器。
- 如果控制器执行成功,控制器将控制权返回给最后一个拦截器。
- 拦截器(InterceptorN) 执行
postHandle
方法,然后将控制权返回给第一个拦截器。 - 拦截器(Interceptor1) 执行
postHandle
方法,然后将控制权返回给最后一个过滤器。 - 如果异常发生,最后一个过滤器将发送错误响应回客户端。如果没有异常并且存在视图,最后一个过滤器将请求转发给视图进行渲染。
- 视图(View) 渲染并返回控制权给最后一个过滤器。
- 最后一个过滤器(FilterN) 将控制权返回给第一个过滤器。
- 第一个过滤器(Filter1) 将最终的HTTP响应发送回客户端。
总结
选择使用拦截器还是过滤器时,需要考虑具体需求。如果需要在Spring MVC的上下文中处理请求,并且需要访问或修改控制器的信息,那么拦截器可能是更好的选择。如果操作需要在更低的级别上处理所有类型的Web资源,或者应用不是基于Spring MVC的,那么过滤器可能更适合需求。
本文皆为个人原创,请尊重创作,未经许可不得转载。
转载自:https://juejin.cn/post/7419306819284205618