过滤器,拦截器,控制器增强器,切面


过滤器、拦截器、@ControllerAdvice、AOP 切面 完整对比
一、底层归属与执行顺序(核心区分点)
1. 所属层级(从外到内)
- Filter 过滤器 → Servlet 规范(Tomcat 容器层面,不属于 Spring)
- Interceptor 拦截器 → SpringMVC 组件(DispatcherServlet 内部)
- @ControllerAdvice 控制器增强 → SpringMVC 控制器层增强
- AOP Aspect 切面 → Spring AOP,Bean 方法层面(Service/Controller 均可)
2. 请求完整执行顺序
浏览器请求 → Tomcat
→ Filter.doFilter() 前置逻辑
→ DispatcherServlet
→ Interceptor.preHandle()
→ Controller方法执行前
→ AOP环绕前置 @Before
→ Controller方法内部
→ 异常抛出 → @ControllerAdvice全局异常处理器
→ AOP环绕后置 @AfterReturning / @AfterThrowing
→ Interceptor.postHandle()(Controller执行完,视图渲染前)
→ 页面渲染
→ Interceptor.afterCompletion()(请求结束)
→ Filter后置逻辑
→ 响应返回浏览器
3. 能否拿到原生对象
|
组件
|
HttpServletRequest/Response
|
Spring 上下文 Model
|
Controller 入参
|
方法入参 / 返回值
|
|
Filter
|
✅ 原生 Servlet 对象
|
❌ 拿不到 Spring Bean
|
❌
|
❌
|
|
Interceptor
|
✅ 封装后的 Spring 对象
|
✅ Model
|
❌ 拿不到接口方法参数
|
❌
|
|
@ControllerAdvice
|
✅
|
✅
|
✅ 可拿到接口参数
|
✅ 返回值统一封装
|
|
AOP 切面
|
❌ 无法直接拿 request(需手动注入 RequestContextHolder)
|
✅
|
✅ 任意 Bean 方法入参
|
✅ 任意方法返回值、异常
|
二、四大组件功能、适用场景、能实现什么
1. Filter 过滤器(Servlet 规范,全局第一层拦截)
核心定位
Tomcat 容器级拦截,所有请求(静态资源、jsp、接口)都会先走 Filter,和 Spring 无关。
可实现功能
- 统一编码设置(request.setCharacterEncoding)
- 跨域 CORS 处理(早期方案)
- 请求黑白名单、IP 限流、非法 URL 拦截
- 登录基础校验(未登录直接返回,不进入 Spring)
- 请求 / 响应流包装(读取原始请求 body,重复消费)
- 静态资源过滤、文件上传基础预处理
局限性
- 拿不到 Controller、Service、方法参数、返回值
- 不能操作 Spring Bean,无法依赖注入 Service
- 只能操作原生 Servlet request/response
典型实现
@WebFilter("/*")
public class CorsFilter implements Filter{}
2. HandlerInterceptor 拦截器(SpringMVC 专属,DispatcherServlet 内)
核心定位
只拦截进入 Controller 的请求,静态资源默认不拦截,属于 SpringMVC 组件。
三个执行方法
- preHandle:Controller 执行前,返回 false 直接中断请求
- postHandle:Controller 执行完毕、视图渲染之前
- afterCompletion:整个请求结束,资源释放
可实现功能
- 登录 token、权限校验(Spring 环境,可注入 Redis / 用户 Service)
- 请求日志打印(请求地址、耗时、用户 ID)
- 统一设置返回头信息
- 存储当前登录用户到 ThreadLocal
- 接口防重复提交(基于 token)
- 视图数据统一填充(postHandle 修改 Model)
局限性
- 无法直接获取 Controller 接口的方法入参、注解
- 不能拦截 Service 层方法,只能作用 Controller 入口
- 拿不到方法返回值,无法统一包装返回体
3. @ControllerAdvice 控制器增强(仅作用 Controller 层)
核心定位
SpringMVC 控制器层专属增强,只针对 @Controller/@RestController。 搭配注解:
- @ExceptionHandler:全局异常处理
- @InitBinder:请求参数绑定、参数校验、日期格式化
- @ModelAttribute:所有 Controller 统一注入公共参数
可实现功能
- 全局统一异常捕获(业务异常、空指针、参数异常统一返回 JSON)
- 请求参数统一格式化(Date、BigDecimal、去除前后空格)
- 公共参数自动注入(全局 userId、租户 id 自动塞到所有接口)
- 统一响应体封装(所有接口返回统一 Result)
- 参数校验统一捕获 @Valid 抛出的 MethodArgumentNotValidException
局限性
- 只生效 Controller,拦截不到 Service、Mapper 方法
- 无法拦截静态资源,不能做容器级过滤
- 无法记录方法执行前后耗时、切面日志
4. AOP Aspect 切面(Spring AOP,任意 Bean 方法拦截)
核心定位
基于动态代理,拦截任意 Spring Bean 的方法(Controller、Service、Mapper 均可),和 MVC 无关。 通知类型:@Before、@AfterReturning、@AfterThrowing、@Around(环绕最强)
可实现功能
- 方法级日志(入参、返回值、执行耗时、异常堆栈)
- 事务管理(@Transactional 底层就是 AOP)
- 接口 / 方法权限校验(注解式权限控制 @RequirePerm)
- 接口限流、分布式锁、缓存切面
- 操作日志记录(用户操作、修改前后数据对比)
- 方法重试、熔断、埋点监控
- Service 层统一异常捕获
局限性
- 默认拿不到原生 HttpServletRequest(需 RequestContextHolder 获取)
- 不能在请求最前端拦截,无法提前阻断请求返回 response
- 静态资源完全无法拦截
三、横向对比总表
|
维度
|
Filter 过滤器
|
Interceptor 拦截器
|
@ControllerAdvice 控制器增强
|
AOP 切面
|
|
所属规范
|
Servlet 容器
|
SpringMVC
|
SpringMVC
|
Spring AOP
|
|
拦截范围
|
全部请求(静态资源、接口、jsp)
|
仅 Controller 接口
|
仅 Controller
|
所有 Spring Bean 方法(Controller/Service)
|
|
执行时机
|
最外层,最先执行
|
DispatcherServlet 内部
|
Controller 方法执行 / 抛出异常时
|
方法调用前后
|
|
获取 request
|
原生对象直接拿
|
Spring 封装后直接拿
|
直接注入
|
需要工具类获取
|
|
获取方法参数
|
不能
|
不能
|
可以
|
可以(JoinPoint)
|
|
获取返回值
|
不能
|
不能
|
可以
|
可以
|
|
依赖注入 Bean
|
不支持
|
支持
|
支持
|
支持
|
|
统一异常处理
|
很难实现
|
不擅长
|
专用,最优解
|
可实现但不推荐
|
|
参数格式化
|
麻烦
|
不支持
|
专用 @InitBinder
|
不适合
|
|
方法耗时、操作日志
|
只能粗粒度请求日志
|
粗粒度请求日志
|
不擅长
|
最优解
|
|
跨域、编码、底层流处理
|
最优解
|
不适合
|
不适合
|
不适合
|
|
登录权限校验
|
简单轻量校验
|
业务权限首选
|
不适合拦截校验
|
注解式权限校验
|
四、业务场景选型建议(开发常用)
- 统一编码、跨域、读取原始 RequestBody → Filter
- 登录 Token 校验、全局请求日志、存储登录用户 → Interceptor
- 全局异常统一返回、参数格式化、统一返回体封装 → @ControllerAdvice
- 方法耗时日志、操作记录、注解权限、缓存、事务、重试 → AOP 切面
五、经典区分面试简答
- Filter 是 Tomcat 层面,早于 Spring,处理底层流、编码;
- Interceptor 是 SpringMVC,专门做接口登录鉴权;
- ControllerAdvice 只管控制器异常、参数绑定、统一返回;
- AOP 是方法层面,面向所有 Bean,做日志、缓存、事务等通用业务逻辑。

浙公网安备 33010602011771号