过滤器、拦截器、AOP切面与其他拦截机制
# 过滤器、拦截器、AOP切面与其他拦截机制
# 概述
在 Java Web 开发中,常用的请求拦截与横切处理机制包括:
- 过滤器(Filter) — Servlet 容器层
- 拦截器(Interceptor) — Spring MVC 层
- AOP 切面(Aspect) — Spring Bean 方法层
- 全局异常处理器(
@RestControllerAdvice) — Controller 异常捕获层 - 跨域配置(CORS) — 跨域请求处理
- 其他机制 —
ResponseBodyAdvice、ErrorController、Spring Security Filter Chain 等
它们都能在业务逻辑执行前后插入额外处理,但作用层级、触发时机、适用场景各不相同。
一句话总结:Filter 管最外层,Interceptor 管 Controller 层,AOP 管任意 Bean 方法层,
@RestControllerAdvice管异常兜底。
整体关系示意:
HTTP 请求
│
▼
┌──────────────────────────────────────────────────┐
│ Spring Security Filter Chain(安全过滤器链) │
│ ┌────────────────────────────────────────────┐ │
│ │ Filter(Servlet 容器层) │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ DispatcherServlet │ │ │
│ │ │ ┌────────────────────────────────┐ │ │ │
│ │ │ │ Interceptor(Spring MVC) │ │ │ │
│ │ │ │ ┌──────────────────────────┐ │ │ │ │
│ │ │ │ │ Controller │ │ │ │ │
│ │ │ │ │ ┌────────────────────┐ │ │ │ │ │
│ │ │ │ │ │ AOP(Spring) │ │ │ │ │ │
│ │ │ │ │ │ ┌──────────────┐ │ │ │ │ │ │
│ │ │ │ │ │ │ Service │ │ │ │ │ │ │
│ │ │ │ │ │ └──────────────┘ │ │ │ │ │ │
│ │ │ │ │ └────────────────────┘ │ │ │ │ │
│ │ │ │ └──────────────────────────┘ │ │ │ │
│ │ │ │ ┌──────────────────────────┐ │ │ │ │
│ │ │ │ │ @RestControllerAdvice │ │ │ │ │ ← 异常捕获
│ │ │ │ │ ResponseBodyAdvice │ │ │ │ │ ← 响应体包装
│ │ │ │ └──────────────────────────┘ │ │ │ │
│ │ │ └────────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ ErrorController(最后防线) │ │
│ └────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
│
▼
HTTP 响应
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 过滤器(Filter)
# 基本概念
过滤器是 Servlet 规范中的组件(javax.servlet.Filter / jakarta.servlet.Filter),运行在 Servlet 容器层,在请求到达 DispatcherServlet 之前和响应离开 DispatcherServlet 之后执行。
- 依赖于 Servlet 容器(如 Tomcat)
- 可以拦截所有请求(包括静态资源、JSP 等)
- 基于回调函数实现
# 核心方法
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 {
// 请求处理前逻辑
System.out.println("Filter - 请求前");
// 放行,将请求传递给下一个 Filter 或 Servlet
chain.doFilter(request, response);
// 响应处理逻辑
System.out.println("Filter - 响应后");
}
@Override
public void destroy() {
// 过滤器销毁,应用关闭时执行一次
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 注册方式
# 方式一:@WebFilter 注解 + @ServletComponentScan
@WebFilter(urlPatterns = "/*", filterName = "myFilter")
public class MyFilter implements Filter {
// ...
}
// 启动类上添加扫描注解
@ServletComponentScan
@SpringBootApplication
public class Application { }
2
3
4
5
6
7
8
9
# 方式二:FilterRegistrationBean(推荐)
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistration() {
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new MyFilter());
registration.addUrlPatterns("/*");
registration.setName("myFilter");
registration.setOrder(1); // 数字越小,优先级越高
return registration;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 常见使用场景
| 场景 | 说明 |
|---|---|
| 字符编码设置 | 统一设置 UTF-8 编码 |
| CORS 跨域处理 | 添加跨域响应头 |
| 请求日志记录 | 记录请求 URL、参数、耗时等 |
| 请求/响应包装 | 如对请求体进行缓存(ContentCachingRequestWrapper) |
| 安全过滤 | 如 XSS 过滤、SQL 注入过滤 |
| 全局异常过滤 | 在最外层捕获未处理的异常 |
# 拦截器(Interceptor)
# 基本概念
拦截器是 Spring MVC 框架中的组件(HandlerInterceptor),运行在 DispatcherServlet 内部,在 Controller 方法执行前后介入。
- 依赖于 Spring MVC 框架
- 只能拦截进入 Controller 的请求(静态资源等不经过拦截器)
- 基于 Java 反射机制实现
# 核心方法
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// Controller 方法执行前调用
// 返回 true:放行;返回 false:中断请求
System.out.println("Interceptor - preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
// Controller 方法执行后、视图渲染前调用
System.out.println("Interceptor - postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 视图渲染完成后调用(无论是否抛出异常)
System.out.println("Interceptor - afterCompletion");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 注册方式
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**") // 拦截路径
.excludePathPatterns("/login", "/static/**"); // 排除路径
}
}
2
3
4
5
6
7
8
9
10
# 三个方法的执行时机
请求 → preHandle → Controller → postHandle → 视图渲染 → afterCompletion
| 方法 | 执行时机 | 异常时是否执行 |
|---|---|---|
preHandle | Controller 执行前 | ✅ 执行 |
postHandle | Controller 执行后、渲染前 | ❌ 不执行(Controller 抛异常时跳过) |
afterCompletion | 视图渲染完成后 | ✅ 执行 |
⚠️ 注意:如果
preHandle返回false,后续拦截器和 Controller 都不会执行,但前面已执行的拦截器的afterCompletion仍会被调用。
# 常见使用场景
| 场景 | 说明 |
|---|---|
| 登录校验 | 检查 Token / Session 是否有效 |
| 权限校验 | 检查用户是否有访问权限 |
| 日志记录 | 记录请求和响应信息 |
| 性能监控 | 统计接口耗时 |
| 请求参数预处理 | 统一添加或修改请求参数 |
💡 项目中已有使用拦截器验证 Bearer Token 的示例,可参考 深入了解 Bearer 模式。
# AOP 切面(Aspect)
# 增加AOP切面
AOP(面向切面编程)是 Spring 框架的核心特性之一,通过动态代理在Bean 方法级别实现横切逻辑。
- 作用于 Spring 容器管理的 Bean
- 基于动态代理(JDK 代理 / CGLIB 代理)实现
- 粒度更细,可以精确到任意方法
关于 AOP 的基础概念和常见注解,可参考 AOP 实战 和 Spring IoC 和 AOP。
# 核心注解
| 注解 | 说明 |
|---|---|
@Aspect | 声明切面类 |
@Pointcut | 定义切入点(匹配哪些方法) |
@Before | 前置通知:方法执行前 |
@After | 后置通知:方法执行后(无论是否异常) |
@AfterReturning | 返回通知:方法正常返回后 |
@AfterThrowing | 异常通知:方法抛出异常后 |
@Around | 环绕通知:方法执行前后(最灵活) |
# 代码示例
@Aspect
@Component
public class LogAspect {
// 定义切入点:匹配 service 包下所有方法
@Pointcut("execution(* com.example.service.*.*(..))")
public void servicePointcut() {}
// 前置通知
@Before("servicePointcut()")
public void before(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("AOP - Before: " + methodName + ", args=" + Arrays.toString(args));
}
// 环绕通知(最常用)
@Around("servicePointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
// 执行前
String methodName = joinPoint.getSignature().getName();
System.out.println("AOP - Around前: " + methodName);
Object result;
try {
// 执行目标方法
result = joinPoint.proceed();
} catch (Throwable e) {
// 异常处理
System.out.println("AOP - Around异常: " + e.getMessage());
throw e;
}
// 执行后
long cost = System.currentTimeMillis() - start;
System.out.println("AOP - Around后: " + methodName + ", 耗时=" + cost + "ms");
return result;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 切入点表达式
| 表达式 | 匹配范围 |
|---|---|
execution(* com.example.service.*.*(..)) | service 包下所有类的所有方法 |
execution(* com.example..*.*(..)) | com.example 及其子包下所有方法 |
@annotation(com.example.MyAnnotation) | 标注了 @MyAnnotation 的方法 |
@within(com.example.MyAnnotation) | 标注了 @MyAnnotation 的类的所有方法 |
bean(userService) | 名称为 userService 的 Bean 的所有方法 |
within(com.example.controller.*) | controller 包下所有类的所有方法 |
# 常见使用场景
| 场景 | 说明 |
|---|---|
| 日志记录 | 记录方法调用参数、返回值、耗时 |
| 权限校验 | 自定义注解 + AOP 实现细粒度权限控制 |
| 事务管理 | @Transactional 底层就是通过 AOP 实现的 |
| 缓存 | @Cacheable 等注解基于 AOP |
| 接口限流 | 自定义注解 + AOP + Redis 实现限流 |
| 参数校验 | 方法执行前校验参数合法性 |
# 全局异常处理器(@RestControllerAdvice)
# 基本概念
@RestControllerAdvice 是 Spring 提供的全局异常处理组件,本质是 @ControllerAdvice + @ResponseBody 的组合。它用于统一捕获 Controller 层抛出的异常,并将其转换为标准化的 JSON 响应。
- 作用于 Controller 层(不拦截 Filter / Interceptor 中的异常)
- 基于
HandlerExceptionResolver机制实现 - 异常被捕获后,不会再传播到 Interceptor 的
postHandle(这也是postHandle在异常时不执行的原因)
💡
@RestControllerAdvice捕获异常后,Interceptor.afterCompletion仍会执行,且ex参数为null(因为异常已被处理)。
# 核心注解
| 注解 | 说明 |
|---|---|
@RestControllerAdvice | 声明全局异常处理类(返回 JSON) |
@ExceptionHandler | 声明处理某种异常的方法 |
@ControllerAdvice | 同上,但需配合 @ResponseBody 才返回 JSON |
# 代码示例
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
log.error("业务异常: {}", e.getMessage(), e);
return Result.fail(e.getCode(), e.getMessage());
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidException(MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldErrors().stream()
.map(error -> error.getField() + ": " + error.getDefaultMessage())
.collect(Collectors.joining("; "));
return Result.fail(400, message);
}
// 处理所有未捕获的异常(兜底)
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
log.error("系统异常: {}", e.getMessage(), e);
return Result.fail(500, "系统内部错误");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 异常处理流程
Controller 抛出异常
│
▼
DispatcherServlet 捕获异常
│
▼
HandlerExceptionResolver 解析
│
▼
@ExceptionHandler 匹配异常类型
│
├── 匹配成功 → 执行处理方法 → 返回 JSON 响应
│
└── 匹配失败 → 异常继续传播 → ErrorController 兜底
│
▼
Interceptor.afterCompletion(ex=null,异常已被处理)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 异常匹配规则
@ExceptionHandler 按异常类型的最近父类匹配:
// 定义异常继承链
class BusinessException extends RuntimeException {}
class OrderNotFoundException extends BusinessException {}
// 处理器
@ExceptionHandler(OrderNotFoundException.class) // 精确匹配,优先级最高
public Result<?> handleOrderNotFound(OrderNotFoundException e) { ... }
@ExceptionHandler(BusinessException.class) // 父类匹配,次之
public Result<?> handleBusiness(BusinessException e) { ... }
@ExceptionHandler(Exception.class) // 兜底,优先级最低
public Result<?> handleAll(Exception e) { ... }
2
3
4
5
6
7
8
9
10
11
12
13
⚠️ 如果有多个
@RestControllerAdvice,可通过@Order控制优先级,数字越小优先级越高。
# 与 Filter / Interceptor / AOP 的关系
| 组件 | 能否捕获异常 | 说明 |
|---|---|---|
| Filter | ❌ 不能被 @RestControllerAdvice 捕获 | Filter 中的异常需自行 try-catch |
| Interceptor | ❌ preHandle / postHandle 中的异常不会被捕获 | afterCompletion 中的异常也不会被捕获 |
| AOP | ❌ AOP 切面中的异常不会被捕获 | 但 AOP @AfterThrowing 可以捕获目标方法的异常 |
| Controller | ✅ 可以被捕获 | @RestControllerAdvice 主要捕获范围 |
| Service | ⚠️ 间接捕获 | Service 抛出的异常传播到 Controller 后可被捕获 |
💡 如果异常在 Filter 或 Interceptor 中抛出,会直接传播到 Servlet 容器,由
ErrorController处理。
# 常见使用场景
| 场景 | 说明 |
|---|---|
| 统一异常响应 | 所有异常返回统一格式的 JSON |
| 业务异常处理 | BusinessException 转换为友好提示 |
| 参数校验异常 | MethodArgumentNotValidException 提取校验错误信息 |
| 权限异常处理 | AccessDeniedException 返回 403 |
| 兜底异常处理 | Exception.class 防止异常堆栈暴露给前端 |
# 跨域配置(CORS)
# 基本概念
CORS(Cross-Origin Resource Sharing,跨域资源共享)是浏览器的安全机制。当前端域名与后端 API 域名不一致时,浏览器会拦截响应。后端需要通过设置 CORS 响应头 来允许跨域访问。
# 三种实现方式
# 方式一:@CrossOrigin 注解(粒度最细)
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:8080", maxAge = 3600)
public class ApiController {
@GetMapping("/data")
@CrossOrigin(origins = "http://localhost:8080") // 方法级别覆盖
public Result<?> getData() {
return Result.success();
}
}
2
3
4
5
6
7
8
9
10
11
# 方式二:WebMvcConfigurer.addCorsMappings(全局配置)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true)
.maxAge(3600); // 预检请求缓存时间(秒)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# 方式三:CorsFilter(推荐,最灵活)
@Configuration
public class CorsFilterConfig {
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowCredentials(true);
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>();
bean.setFilter(new CorsFilter(source));
bean.setOrder(0); // 优先级最高,确保在其他 Filter 之前处理 CORS
return bean;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 三种方式对比
| 对比项 | @CrossOrigin | WebMvcConfigurer | CorsFilter |
|---|---|---|---|
| 粒度 | 类 / 方法级别 | 全局路径级别 | 全局路径级别 |
| 执行层级 | Spring MVC 层 | Spring MVC 层 | Servlet 容器层 |
| 优先级 | 低 | 中 | 高(可设置 order) |
| 灵活性 | 低 | 中 | 高 |
| 推荐场景 | 少量接口跨域 | 全局简单跨域 | 全局复杂跨域 / 有 Filter 拦截 |
⚠️ 如果项目中使用了 Spring Security,CORS 需在 Security Filter Chain 中配置,否则可能在 Security 拦截之前就被拒绝:
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.cors(Customizer.withDefaults()) // 启用 CORS .csrf().disable() ...; return http.build(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("http://localhost:8080")); config.setAllowedMethods(Arrays.asList("*")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# CORS 预检请求(Preflight)
浏览器对于非简单请求会先发送一个 OPTIONS 方法的预检请求:
// 简单请求(不触发预检)
GET /api/data
Content-Type: text/plain
// 非简单请求(触发预检)
POST /api/data
Content-Type: application/json
Authorization: Bearer xxx
2
3
4
5
6
7
8
预检请求流程:
浏览器 → OPTIONS /api/data(预检请求)
│
▼
后端返回 CORS 响应头
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600
│
▼
浏览器检查通过 → 发送真实请求
浏览器检查失败 → 拦截请求,不发送
2
3
4
5
6
7
8
9
10
11
12
💡
maxAge设置预检缓存时间,缓存期内浏览器不会重复发送预检请求。
# 其他拦截 / 捕获机制
除了 Filter、Interceptor、AOP、@RestControllerAdvice,Spring 生态中还有以下机制可以拦截或捕获请求 / 异常:
# ResponseBodyAdvice(响应体增强)
在 Controller 方法返回后、响应体写入前,对返回值进行统一包装。
@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
// 对所有返回值生效
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType,
MediaType selectedContentType,
Class selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
// 统一包装为 Result 格式
if (body instanceof Result) {
return body; // 已包装,直接返回
}
return Result.success(body);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| 特性 | 说明 |
|---|---|
| 作用时机 | Controller 返回后、JSON 序列化前 |
| 适用场景 | 统一响应体包装、敏感数据脱敏 |
与 @RestControllerAdvice 关系 | 可组合使用,异常处理 + 响应包装 |
# RequestBodyAdvice(请求体增强)
在请求体反序列化前后插入处理逻辑。
@RestControllerAdvice
public class GlobalRequestAdvice implements RequestBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
// 请求体读取前处理(如解密)
return inputMessage;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
// 请求体读取后处理(如参数校验)
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| 特性 | 说明 |
|---|---|
| 作用时机 | 请求体反序列化前后 |
| 适用场景 | 请求参数解密、参数预处理 |
# ErrorController(兜底异常处理)
当异常未被任何 @ExceptionHandler 捕获时,Spring Boot 会转发到 /error 路径,由 ErrorController 处理。
@RestController
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public Result<Void> handleError(HttpServletRequest request) {
Integer status = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
if (status != null && status == 404) {
return Result.fail(404, "资源不存在");
}
return Result.fail(500, "系统内部错误");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
| 特性 | 说明 |
|---|---|
| 触发条件 | 异常未被 @ExceptionHandler 捕获 / Filter 中抛出异常 |
| 执行层级 | Servlet 容器层(最后防线) |
| 适用场景 | 兜底异常处理、404 页面定制 |
💡 Filter / Interceptor 中抛出的异常无法被
@RestControllerAdvice捕获,最终会由ErrorController处理。
# Spring Security Filter Chain(安全过滤器链)
Spring Security 通过一组 Security Filter 实现认证与授权,这些 Filter 在普通 Filter 之前执行。
HTTP 请求
│
▼
SecurityFilterChain(Spring Security)
│ ├── SecurityContextPersistenceFilter
│ ├── UsernamePasswordAuthenticationFilter
│ ├── JwtAuthenticationFilter(自定义)
│ ├── ExceptionTranslationFilter
│ └── FilterSecurityInterceptor
│
▼
普通 Filter → DispatcherServlet → Interceptor → Controller
2
3
4
5
6
7
8
9
10
11
12
| 特性 | 说明 |
|---|---|
| 执行层级 | 在普通 Filter 之前 |
| 核心组件 | SecurityFilterChain |
| 适用场景 | 认证、授权、安全防护 |
💡 关于 Spring Security 的详细使用,可参考 安全框架 Spring Security 入门。
# Spring Cloud Gateway GlobalFilter(网关层过滤器)
在微服务架构中,Spring Cloud Gateway 提供 GlobalFilter 在网关层拦截所有请求。
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100; // 优先级越高,数字越小
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| 特性 | 说明 |
|---|---|
| 执行层级 | 网关层(微服务之前) |
| 适用场景 | 统一认证、限流、日志、灰度发布 |
# HandlerExceptionResolver(异常解析器)
Spring MVC 内部的异常解析接口,@ExceptionHandler 底层依赖 ExceptionHandlerExceptionResolver 实现。
@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
// 自定义异常解析逻辑
response.setStatus(500);
try {
response.getWriter().write(JSON.toJSONString(Result.fail(500, ex.getMessage())));
} catch (IOException e) {
// ignore
}
return new ModelAndView(); // 返回空的 ModelAndView 表示已处理
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
💡 通常不需要直接实现
HandlerExceptionResolver,使用@RestControllerAdvice+@ExceptionHandler即可。
# 各机制总览
| 机制 | 层级 | 拦截范围 | 典型场景 |
|---|---|---|---|
| Filter | Servlet 容器 | 所有请求 | 编码、CORS、XSS |
| Interceptor | Spring MVC | Controller 请求 | 登录校验、权限控制 |
| AOP | Spring Bean | Bean 方法 | 日志、事务、限流 |
@RestControllerAdvice | Spring MVC | Controller 异常 | 统一异常处理 |
ResponseBodyAdvice | Spring MVC | Controller 返回值 | 统一响应包装 |
RequestBodyAdvice | Spring MVC | 请求体 | 请求解密、预处理 |
ErrorController | Servlet 容器 | 未捕获异常 | 兜底异常、404 |
| Security Filter Chain | Spring Security | 所有请求 | 认证、授权 |
| Gateway GlobalFilter | 网关层 | 网关所有请求 | 统一认证、限流 |
HandlerExceptionResolver | Spring MVC | Controller 异常 | 自定义异常解析 |
# 各机制对比
| 对比项 | Filter(过滤器) | Interceptor(拦截器) | AOP(切面) | @RestControllerAdvice |
|---|---|---|---|---|
| 技术规范 | Servlet 规范 | Spring MVC | Spring AOP | Spring MVC |
| 运行层级 | Servlet 容器 | DispatcherServlet 内部 | Spring Bean 代理层 | DispatcherServlet 内部 |
| 拦截范围 | 所有请求(含静态资源) | Controller 请求 | Spring Bean 的方法 | Controller 抛出的异常 |
| 实现机制 | 回调函数 | Java 反射 | 动态代理(JDK / CGLIB) | HandlerExceptionResolver |
| 能否获取 Bean | ❌ 不能直接获取(需通过 ApplicationContext) | ✅ 可以 | ✅ 可以 | ✅ 可以 |
| 能否修改请求/响应对象 | ✅ 可以(可包装为 HttpServletRequestWrapper) | ✅ 可以 | ❌ 不直接操作请求/响应 | ✅ 可以(通过 @ResponseBody) |
| 粒度 | URL 级别 | Controller 方法级别 | 任意 Bean 方法级别 | 异常类型级别 |
| 异常处理 | 需自行 try-catch | afterCompletion 可获取异常 | @AfterThrowing 可捕获异常 | @ExceptionHandler 统一捕获 |
| 执行顺序 | 按 FilterRegistrationBean 的 order | 按 addInterceptor 的注册顺序 | 按 @Order 注解或 @Priority | 按 @Order + 异常类型匹配 |
| 典型场景 | 编码、CORS、XSS 过滤 | 登录校验、权限控制 | 日志、事务、缓存、限流 | 统一异常响应、参数校验 |
# 执行顺序详解
# 完整执行流程
当 Filter、Interceptor、AOP、@RestControllerAdvice 同时存在时,执行顺序如下:
请求到达
│
▼
Filter.doFilter (前置)
│
▼
DispatcherServlet
│
▼
Interceptor.preHandle
│
▼
AOP @Before / @Around (前置)
│
▼
Controller 方法
│
├─ 正常返回 ─→ AOP @After / @Around (后置) / @AfterReturning
│ │
│ ▼
│ Interceptor.postHandle
│ │
│ ▼
│ 视图渲染
│
└─ 抛出异常 ─→ AOP @AfterThrowing / @After
│
▼
@RestControllerAdvice @ExceptionHandler
│
▼
Interceptor.afterCompletion (ex=null)
│
▼
Filter.doFilter (后置)
│
▼
响应返回
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 简化记忆
请求: Filter前 → Interceptor前 → AOP前 → Controller
正常: Controller → AOP后 → Interceptor后 → Filter后
异常: Controller → AOP异常 → @RestControllerAdvice → Interceptor.afterCompletion → Filter后
2
3
关键点:Filter 最先执行、最后结束;AOP 最靠近业务方法;
@RestControllerAdvice在异常时接管响应。三者是洋葱模型——外层先进入后退出。
# 多个 Filter / Interceptor 的顺序
# 多个 Filter
按 FilterRegistrationBean 的 order 值从小到大执行:
// order=1 的 Filter 先执行
registration.setOrder(1);
2
Filter1前 → Filter2前 → ... → Servlet → ... → Filter2后 → Filter1后
# 多个 Interceptor
按 addInterceptor 的注册顺序执行:
registry.addInterceptor(interceptorA); // 先注册,先执行
registry.addInterceptor(interceptorB); // 后注册,后执行
2
A.preHandle → B.preHandle → Controller → B.postHandle → A.postHandle → B.afterCompletion → A.afterCompletion
⚠️ 注意
postHandle和afterCompletion的顺序是反过来的(类似栈结构)。
# 验证执行顺序的示例
定义一个 Filter、一个 Interceptor、一个 AOP 切面,在 Controller 方法上观察输出:
// Filter
System.out.println("1. Filter 前");
chain.doFilter(request, response);
System.out.println("6. Filter 后");
// Interceptor
System.out.println("2. Interceptor preHandle");
// ...
System.out.println("4. Interceptor postHandle");
// ...
System.out.println("5. Interceptor afterCompletion");
// AOP @Around
System.out.println("3. AOP 前");
Object result = joinPoint.proceed();
System.out.println("3.5 AOP 后");
// Controller
System.out.println("3.1 Controller 执行");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
输出结果:
1. Filter 前
2. Interceptor preHandle
3. AOP 前
3.1 Controller 执行
3.5 AOP 后
4. Interceptor postHandle
5. Interceptor afterCompletion
6. Filter 后
2
3
4
5
6
7
8
# 异常情况下的执行顺序
# Controller 抛出异常
Filter前 → Interceptor.preHandle → AOP前 → Controller(抛异常)
→ AOP @AfterThrowing / @After
→ @RestControllerAdvice @ExceptionHandler(捕获异常,生成响应)
→ Interceptor.afterCompletion(ex=null,异常已被处理)
→ Filter后
2
3
4
5
| 组件 | 异常时是否执行 |
|---|---|
| Filter 后置逻辑 | ✅ 执行 |
Interceptor postHandle | ❌ 不执行 |
Interceptor afterCompletion | ✅ 执行(ex 为 null,异常已被 @RestControllerAdvice 处理) |
AOP @AfterReturning | ❌ 不执行 |
AOP @AfterThrowing | ✅ 执行 |
AOP @After | ✅ 执行 |
@RestControllerAdvice | ✅ 执行(捕获 Controller 异常) |
💡 这就是为什么
afterCompletion适合做资源清理——无论是否异常都会执行。
# preHandle 返回 false
Filter1前 → Filter2前 → Interceptor1.preHandle(返回true)
→ Interceptor2.preHandle(返回false) ← 中断
→ Interceptor1.afterCompletion ← 已执行的拦截器仍会回调
→ Filter2后 → Filter1后
2
3
4
Controller、AOP、
postHandle都不会执行。
# 参数解析异常
参数解析发生在 AOP 之前,
所以 MethodArgumentNotValidException、HttpMessageNotReadableException(请求体格式错误)、MissingServletRequestParameterException(缺少必填参数)这些都打不到 AOP 日志里。
请求 → Filter → DispatcherServlet → 参数解析(@RequestBody 反序列化 / @Valid 校验)
→ 失败直接抛异常,Controller 方法根本没被调用
→ AOP 包裹的是 Controller 方法,方法没执行,AOP 不触发
→ 异常直接到 @RestControllerAdvice
2
3
4
# 如何选择?
# 决策流程
需要拦截所有请求(含静态资源)?
→ 是 → 用 Filter
→ 否 → 需要操作 HttpServletRequest / HttpServletResponse?
→ 是 → 用 Interceptor
→ 否 → 需要拦截非 Controller 的 Bean 方法?
→ 是 → 用 AOP
→ 否 → 需要统一处理 Controller 异常?
→ 是 → 用 @RestControllerAdvice
→ 否 → 需要统一包装响应体?
→ 是 → 用 ResponseBodyAdvice
→ 否 → 用 Interceptor
2
3
4
5
6
7
8
9
10
11
# 场景速查
| 需求 | 推荐方案 |
|---|---|
| 统一字符编码 | Filter |
| CORS 跨域 | Filter(或 Spring CORS 配置) |
| XSS / SQL 注入过滤 | Filter |
| 登录状态校验 | Interceptor |
| 接口权限控制 | Interceptor |
| 接口耗时统计 | Interceptor 或 AOP |
| Service 方法日志 | AOP |
| 自定义注解实现功能(限流等) | AOP |
| 事务管理 | AOP(@Transactional) |
| 请求体缓存(可重复读取) | Filter |
| 统一异常处理 | @RestControllerAdvice |
| 统一响应体包装 | ResponseBodyAdvice |
| 请求参数解密 | RequestBodyAdvice |
| 兜底异常 / 404 处理 | ErrorController |
| 认证授权(Spring Security) | Security Filter Chain |
| 网关层统一拦截 | Gateway GlobalFilter |
# 常见问题
# 1. Filter 中无法注入 Bean?
原因:Filter 由 Servlet 容器管理,早于 Spring 容器初始化。
解决方法:
// 方式一:使用 FilterRegistrationBean 注册(推荐)
@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistration() {
FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(myFilter); // myFilter 由 Spring 注入,可以使用 @Autowired
registration.addUrlPatterns("/*");
return registration;
}
// 方式二:通过 ApplicationContextAware 获取
2
3
4
5
6
7
8
9
10
# 2. Interceptor 中无法注入 Bean?
解决方法:确保 Interceptor 通过 @Component 注册为 Bean,并在 addInterceptors 中注入:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor; // 注入即可使用 @Autowired
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor).addPathPatterns("/**");
}
}
2
3
4
5
6
7
8
9
10
11
# 3. AOP 不生效?
常见原因:
| 原因 | 说明 | 解决方法 |
|---|---|---|
| 目标类未由 Spring 管理 | AOP 只能代理 Spring Bean | 添加 @Component 等注解 |
| 内部方法调用 | this.method() 不走代理 | 使用 AopContext.currentProxy() 或注入自身 |
目标方法是 final 或 static | 无法被代理覆盖 | 去除 final / static 修饰 |
未添加 @EnableAspectJAutoProxy | Spring Boot 默认已开启,纯 Spring 项目需手动添加 | 添加注解 |
内部调用问题示例:
@Service
public class UserService {
public void methodA() {
// ❌ 直接调用,不经过代理,AOP 不生效
this.methodB();
}
@LogAnnotation // 期望被 AOP 拦截
public void methodB() { }
// ✅ 解决方法:通过代理对象调用
public void methodA_fixed() {
((UserService) AopContext.currentProxy()).methodB();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 4. Filter 和 Interceptor 都能做登录校验,选哪个?
推荐 Interceptor,原因:
- 可以方便地注入 Service 进行 Token 校验
- 只拦截 Controller 请求,不影响静态资源
preHandle返回false即可中断请求,语义清晰
如果需要在请求最外层统一处理(如网关层),则用 Filter。
# 总结
| 要点 | Filter | Interceptor | AOP | @RestControllerAdvice |
|---|---|---|---|---|
| 层级 | Servlet 容器 | Spring MVC | Spring Bean 代理 | Spring MVC |
| 触发时机 | 请求最外层 | Controller 前后 | Bean 方法前后 | Controller 抛出异常时 |
| 执行顺序 | 最先执行,最后结束 | 中间层 | 最内层,最靠近业务 | 异常时接管响应 |
| 核心接口 | Filter | HandlerInterceptor | @Aspect + @Pointcut | @ExceptionHandler |
| 选择原则 | 需要拦截所有请求 / 操作请求响应对象 | 需要拦截 Controller / 可注入 Bean | 需要拦截任意 Bean 方法 / 细粒度控制 | 需要统一处理 Controller 异常 |
记忆口诀:Filter 在外管全局,Interceptor 居中管 Controller,AOP 在内管方法,
@RestControllerAdvice兜底管异常。洋葱层层包裹,外层先进后出,异常由内向外传递,@RestControllerAdvice截断异常链。