谈谈 Spring 的过滤器和拦截器
前言
我们在进行 Web 应用开发时,时常需要对请求进行拦截或处理,故 Spring 为我们提供了过滤器和拦截器来应对这种情况。那么两者之间有什么不同呢?本文将详细讲解两者的区别和对应的使用场景。
(本文的代码实现首先是基于 SpringBoot,Spring 的实现方式仅简单描述)

1. 过滤器
1.1. 什么是过滤器
过滤器(Filter),是 Servlet 规范规定的,在 Servlet 前执行的。用于拦截和处理 HTTP 请求和响应,可用于身份认证、授权、日志记录和设置字符集(CharacterEncodingFilter)等场景。
过滤器位于整个请求处理流程的最前端,因此在请求到达 Controller 层前,都会先被过滤器处理。
过滤器可以拦截多个请求或响应,一个请求或响应也可以被多个过滤器拦截。
1.2. 如何创建过滤器
Filter 的生命周期对应的三个关键方法:
| 方法 | 说明 |
|---|---|
| init() | 当请求发起时,会调用 init() 方法初始化 Filter 实例,仅初始化一次。若需要设置初始化参数的时可调用该方法。 |
| doFilter() | 拦截要执行的请求,对请求和响应进行处理。 |
| destroy() | 请求结束时调用该方法销毁 Filter 的实例。 |
下面将介绍二种方法创建 Filter。
1.2.1 实现 Filter 接口
1.创建 Filter 处理类,实现javax.servlet.Filter接口,加上@WebFilter注解配置拦截 Url,但是不能指定过滤器执行顺序,也可通过web.xml配置。
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 用于完成 Filter 的初始化
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("过滤器已经拦截成功!!!");
// 执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。
chain.doFilter(request,response);
}
@Override
public void destroy() {
// 用于 Filter 销毁前,完成某些资源的回收;
Filter.super.destroy();
}
}
2.在启动类添加注解@ServletComponentScan ,让 Spring 可以扫描到。
@SpringBootApplication
@ServletComponentScan
public class MyFilterDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyFilterDemoApplication.class, args);
}
}
3.创建 Controller 发起 Url 请求。
@RestController
public class MyFilterController {
@GetMapping("/testFilter")
public String testFilter(){
return "Hello World";
}
}
拦截结果

1.2.2. 通过@Component 注解
1.创建 Filter 处理类,实现javax.servlet.Filter接口,加@Component注解。
- 可以使用
@Order注解保证过滤器执行顺序,不加则按照类名排序。 - 过滤器不能指定拦截的url , 只能默认拦截全部。
@Component
@Order(1)
public class MyComponentFilter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("我是过滤器1已经拦截成功!!!");
chain.doFilter(request,response);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
@Component
@Order(2)
public class MyComponentFilter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
System.out.println("我是过滤器2已经拦截成功!!!");
chain.doFilter(request,response);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
2-3 步骤同 1.2.1,结果如下。

2. 拦截器
2.1. 什么是拦截器
拦截器(Interceptor),和Servlet无关,由Spring框架实现。可用于身份认证、授权、日志记录、预先设置数据以及统计方法的执行效率等。
一般基于 Java 的反射机制实现,属于AOP的一种运用。
目前了解的 Spring 中的拦截器有:
- HandlerInterceptor
- MethodInterceptor
2.2. HandlerInterceptor 拦截器
2.2.1简介
HandlerInterceptor 类似 Filter,拦截的是请求地址 ,但提供更精细的的控制能力,这里注意下必须过DispatcherServlet 的请求才会被拦截。
它允许你在请求处理前、处理后以及视图渲染完成前执行自定义逻辑,可以用来对请求地址做一些认证授权、预处理,也可以计算一个请求的响应时间等,还可以处理跨域(CORS)问题。
简单的执行流程描述:
- 请求到达 DispatcherServlet,然后发送至 Interceptor,执行 preHandler;
- 请求到达 Controller,请求结束后,执行 postHandler。
2.2.2如何实现
- 创建 Interceptor 类,实现
HandlerInterceptor接口,重写 3 个方法,加@Component注解。

@Component
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//请求开始时间
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
System.out.println("startTime : " + new Date(startTime));
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
long startTime = (Long)request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
// 统计耗时
long executeTime = endTime - startTime;
System.out.println("executeTime : " + executeTime + "ms");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
2.配置拦截器,实现WebMvcConfigurer接口,加@Configuration注解并重写addInterceptors方法。
@Configuration
public class MyWebConfigurer implements WebMvcConfigurer {
@Resource
private MyHandlerInterceptor myHandlerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> patterns = new ArrayList<>();
patterns.add("/test/handlerInterceptor");
registry.addInterceptor(myHandlerInterceptor)
.addPathPatterns(patterns) // 需要拦截的请求
.excludePathPatterns(); // 不需要拦截的请求
}
}
拦截结果如下:

Spring 项目如何实现?
可通过使用mvc:interceptors标签来声明需要加入到 SpringMVC 拦截器链中的拦截器。
2.3. MethodInterceptor 拦截器
2.3.1. 简介
MethodInterceptor 是 AOP 中的拦截器,它拦截的目标是方法,可以不是 Controller 中的方法。
在对一些普通的方法上的拦截可以使用该拦截器,这是 HandlerInterceptor 无法实现的。
可用来进行方法级别的身份认证、授权以及日志记录等,也可基于自定义注解实现一些通用的方法增强功能。
2.3.2. 如何实现
MethodInterceptor 是基于 AOP 实现的,所以根据不同的代理有多种实现方式,更多的实现方式和原理我将在整理 Spring AOP 的时候详细接受。
这里我将介绍通过BeanNameAutoProxyCreator自动代理实现拦截。该类是基于 Bean 名称的自动代理,可以针对特定的Bean进行个性化的 AOP 配置。
1.创建简单的需要拦截的方法。
public interface UserService {
public String getUser();
}
@Component
public class UserServiceImpl implements UserService{
@Override
public String getUser() {
return "我是福星";
}
}
2.创建 Interceptor 类,实现MethodInterceptor接口,重写invoke方法,加@Component注解。
@Component
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("进入拦截,方法执行前,拦截方法是:" + invocation.getMethod().getName());
Object result = invocation.proceed();
System.out.println("方法执行后");
return result;
}
}
3.配置自动代理,加@Configuration注解并创建自动代理BeanNameAutoProxyCreator。
@Configuration
public class MyMethodConfigurer {
@Resource
private MyMethodInterceptor myMethodInterceptor;
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
// 使用BeanNameAutoProxyCreator来创建代理
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
// 指定一组需要自动代理的Bean名称,Bean名称可以使用*通配符
beanNameAutoProxyCreator.setBeanNames("user*");
//设置拦截器名称,这些拦截器是有先后顺序的
beanNameAutoProxyCreator.setInterceptorNames("myMethodInterceptor");
return beanNameAutoProxyCreator;
}
}
发起请求后,调用该方法前会进行拦截。

3. 总结
过滤器一般用于对 Servlet 请求和响应进行通用性的处理,通常关注请求和响应内容,而不涉及具体的业务逻辑。而拦截器用于对 SpringMVC 的请求和响应进行特定的业务处理,通常与控制器层的请求处理有关。
不论是过滤器和拦截器,都可以有多个。执行顺序上拦截器是由配置中的顺序决定,而过滤器可通过@Component+@Order决定,也可由web.xml文件中的配置顺序决定。
总的来说,拦截器的使用更加灵活,Filter 能做的事情,拦截器也能做。Filter 一般用于对 URL 请求做编码处理、过滤无用参数、安全校验(比如登陆态校验),如果涉及业务逻辑上的,还是建议用拦截器。
谈谈 Spring 的过滤器和拦截器的更多相关文章
- spring boot 过滤器、拦截器的区别与使用
原文:https://blog.csdn.net/heweimingming/article/details/79993591 拦截器与过滤器的区别: 1.过滤器和拦截器触发时机不一样,过滤器是在请求 ...
- Spring Boot实战:拦截器与过滤器
一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...
- Spring Boot使用过滤器和拦截器分别实现REST接口简易安全认证
本文通过一个简易安全认证示例的开发实践,理解过滤器和拦截器的工作原理. 很多文章都将过滤器(Filter).拦截器(Interceptor)和监听器(Listener)这三者和Spring关联起来讲解 ...
- spring中的监视器,过滤器,拦截器
1.监视器 (1)首先监视器是观察者模式的实现,在我之前的博客中有关于监视器模式的解释.监视器相当于观察者 (2)我们在springMvc中最常见的监视器 ContextLoaderlistener ...
- spring过滤器和拦截器的区别和联系
一 简介 (1)过滤器: 依赖于servlet容器,是JavaEE标准,是在请求进入容器之后,还未进入Servlet之前进行预处理,并且在请求结束返回给前端这之间进行后期处理.在实现上基于函数回调,可 ...
- Spring Boot 如何使用拦截器、过滤器、监听器?
过滤器 过滤器的英文名称为 Filter, 是 Servlet 技术中最实用的技术. 如同它的名字一样,过滤器是处于客户端和服务器资源文件之间的一道过滤网,帮助我们过滤掉一些不符合要求的请求,通常用作 ...
- Spring Boot中使用过滤器和拦截器
过滤器(Filter)和拦截器(Interceptor)是Web项目中常用的两个功能,本文将简单介绍在Spring Boot中使用过滤器和拦截器来计算Controller中方法的执行时长,并且简单对比 ...
- Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter的使用
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的 而在Spring中,基于Filter这种方式可以实现Bean预处理.后处理. 比如注入FilterRegistrationBean,然后 ...
- spring:过滤器和拦截器
过滤器:网络通信模型的会话层控制: 拦截器:事务处理的aop注入(生命周期监控). 对于Servlet Filter,官方文档中说的很好, 并且给出了常见的应用场景. A filter is an o ...
- springboot(五)过滤器和拦截器
前言 过滤器和拦截器二者都是AOP编程思想的提现,都能实现诸如权限检查.日志记录等.二者有一定的相似之处,不同的地方在于: Filter是servlet规范,只能用在Web程序中,而拦截器是Sprin ...
随机推荐
- #根号分治,前缀和,双指针#CF1446D2 Frequency Problem (Hard Version)
题目 给定一个长度为 \(n\) 的序列,问是否存在一个最长的区间使得至少存在两个众数. 分析 实际上 Easy Version 是用来启发大于根号的做法的. 众数可以说有一个性质吧,答案区间中的其中 ...
- #斐波那契#洛谷 3424 [POI2005] SUM-Fibonacci Sums
题目 已知\(x,y\)的斐波那契表示,求\(x+y\)的斐波那契表示 分析 显然得到两条性质: \(f_{i+1}=f_{i-1}+f_i\) \(2f_i=f_{i+1}+f_{i-2}\) 那么 ...
- OpenHarmony AI框架开发指导
一.概述 1.功能简介 AI 业务子系统是 OpenHarmony 提供原生的分布式 AI 能力的子系统.AI 业务子系统提供了统一的 AI 引擎框架,实现算法能力快速插件化集成. AI 引擎框架主要 ...
- Java 数据类型详解与类型转换技巧
Java 数据类型 Java 中的变量必须是指定的数据类型: int myNum = 5; // 整数 float myFloatNum = 5.99f; // 浮点数 char myLetter = ...
- 十城百校联动!HDC.Together 2023 HarmonyOS学生公开课与千余名校园学子见证鸿蒙力量
8月6日,HDC.Together2023 HarmonyOS学生公开课在东莞松山湖举办.有来自清华大学.北京大学.哈尔滨工业大学等全国百余所高校,千余名学生开发者齐聚会场,与华为高级技术专家.生 ...
- centos 6.4下fdisk分区、格式化、挂载新硬盘
centos 6.4下fdisk分区.格式化.挂载新硬盘 作者: cat 日期: 2013 年 9 月 10 日 发表评论 (0) 查看评论 1.# fdisk -l 查看当前磁盘信息,就会发现最下面 ...
- 重新整理 .net core 实践篇———承载[外篇]
前言 简单介绍一下承载. 正文 名称叫做承载,其实就是.net core 定义的一套长期运行的服务的规范. 这个服务可以是web服务,也可以是其他服务,比如tcp,或者一些监控服务. 这里以监控服务为 ...
- css 你真的了解padding吗?
前言 padding 简写属性在一个声明中设置所有内边距属性,实际上在使用过程中它对block元素和内联元素的处理是不一样的. 正文 对于block元素 如果宽度非auto那么容器会变大,如果容器宽度 ...
- WPF随笔收录-实时绘制心率曲线
一.前言 在自己的项目中,涉及到实时心率曲线的绘制,项目上的曲线绘制,一般很难找到能直接用的第三方库,而且有些还是定制化的功能,所以还是自己绘制比较方便.很多人一听到自己画就害怕,感觉很难,今天就分享 ...
- echarts使用与踩坑
0.踩坑点 1.当图表不显示在页面(display:none)执行resize可能会导致图表样式混乱 1. 官网示例 import * as echarts from 'echarts'; // 基于 ...