Spring Boot请求处理组件对比详解
Spring Boot 提供了多种组件来处理请求的不同阶段过滤器、拦截器、AOP、监听器、ControllerAdvice、参数/返回值处理器。它们功能上有重叠但各有定位初学者容易混淆。本文系统讲解每种组件的原理、用法并从执行顺序、适用场景、功能交叉点等维度进行横向对比帮助在不同场景下做出正确选型。一、整体架构与执行流程1.1 请求处理全链路一个 HTTP 请求到达 Spring Boot 应用后会依次经过以下组件HTTP 请求 | v ┌─────────────────────────────────────────────────────────┐ │ Servlet 容器Tomcat │ │ ↓ │ │ Filter过滤器─── 可拦截请求和响应 │ │ ↓ │ │ DispatcherServlet │ │ ├──→ HandlerInterceptor.preHandle()拦截器-前置 │ │ ├──→ HandlerMethodArgumentResolver参数处理器 │ │ ├──→ Controller 方法被 AOP 环绕 │ │ │ └──→ AOP Before / Around │ │ ├──→ HandlerMethodReturnValueHandler返回值处理器 │ │ ├──→ HandlerInterceptor.postHandle()拦截器-后置 │ │ └──→ HandlerInterceptor.afterCompletion()拦截器-完成│ │ │ │ 异常分支 │ │ 任何阶段抛出异常 → RestControllerAdvice 捕获 │ │ │ │ 事件分支 │ │ ServletRequestListener / ApplicationEvent 贯穿全程 │ └─────────────────────────────────────────────────────────┘ | v HTTP 响应1.2 六大组件定位组件所属层级核心职责一句话定位FilterServlet 容器请求/响应的过滤与包装最外层的守门员InterceptorSpring MVCController 前后拦截Controller 的贴身保镖AOPSpring 容器方法级别的横切逻辑任意 Bean 方法的拦截器ListenerServlet / Spring事件监听与回调全局事件的观察者ControllerAdviceSpring MVC全局异常处理与数据绑定Controller 的后勤保障ArgumentResolverSpring MVC自定义参数解析请求参数 → Controller 入参ReturnValueHandlerSpring MVC自定义返回值处理Controller 返回值 → 响应二、Filter过滤器2.1 原理Filter 是 Servlet 规范的一部分运行在 DispatcherServlet 之前和之后可以拦截所有 HTTP 请求包括静态资源。请求 → FilterChain Filter1.doFilter() Filter2.doFilter() DispatcherServlet Filter2响应 Filter1响应 响应2.2 用法import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.io.IOException; /** * 请求日志过滤器 */ Component Order(1) public class RequestLogFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; long start System.currentTimeMillis(); System.out.println([Filter] 请求进入: req.getMethod() req.getRequestURI()); // 放行到下一个 Filter 或 DispatcherServlet chain.doFilter(request, response); long cost System.currentTimeMillis() - start; System.out.println([Filter] 请求完成: req.getRequestURI() 耗时 cost ms 状态码 resp.getStatus()); } }也可以通过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 FilterRegistrationBeanRequestLogFilter requestLogFilter() { FilterRegistrationBeanRequestLogFilter bean new FilterRegistrationBean(); bean.setFilter(new RequestLogFilter()); bean.addUrlPatterns(/*); bean.setOrder(1); bean.setName(requestLogFilter); return bean; } }2.3 特点特点说明拦截范围所有请求包括静态资源、非 Controller 请求能否访问 Spring Bean可以通过注入能否获取 Controller 信息不能不知道哪个 Controller 处理能否修改请求/响应体可以通过包装 HttpServletRequestWrapper执行时机DispatcherServlet 之前和之后三、Interceptor拦截器3.1 原理Interceptor 是 Spring MVC 提供的机制运行在 DispatcherServlet 内部可以感知到HandlerExecutionChain即哪个 Controller 方法将要执行。DispatcherServlet ├── preHandle() → Controller 执行前 ├── postHandle() → Controller 返回后视图渲染前 └── afterCompletion() → 视图渲染完成后即使有异常也会执行3.2 用法import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; /** * 登录校验拦截器 */ Component public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (token null || token.isEmpty()) { response.setStatus(401); response.getWriter().write(未登录); return false; // 中断请求 } System.out.println([Interceptor] preHandle: token token); return true; // 放行 } Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println([Interceptor] postHandle: Controller 执行完毕); } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println([Interceptor] afterCompletion: 请求结束, ex ex); } }注册拦截器并配置拦截路径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 WebMvcConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns(/api/**) // 拦截路径 .excludePathPatterns(/api/login); // 排除路径 } }3.3 特点特点说明拦截范围Controller 请求不拦截静态资源能否获取 Controller 信息可以handler 参数包含 HandlerMethod能否中断请求可以preHandle 返回 falsepreHandleController 执行前返回 false 中断postHandleController 正常返回后执行抛异常则不执行afterCompletion最终执行无论是否异常注意postHandle在 Controller 抛出异常时不会执行但afterCompletion一定会执行。四、AOP面向切面编程4.1 原理AOP 是 Spring 容器级别的机制基于动态代理JDK 或 CGLIB可以拦截 Spring Bean 的方法调用。它不局限于 Controller可以作用于任何 Bean。调用 target.method() ↓ 代理对象 ├── Before → 方法执行前 ├── AfterReturning → 方法正常返回后 ├── AfterThrowing → 方法抛出异常后 ├── After → 方法结束后无论成功失败 └── Around → 环绕最强大可控制是否执行4.2 用法import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; /** * 接口耗时统计切面 */ Slf4j Aspect Component public class TimeLogAspect { /** * 定义切入点controller 包下所有 public 方法 */ Pointcut(execution(public * com.example.demo.controller.*.*(..))) public void controllerPointcut() { } /** * 环绕通知统计方法执行耗时 */ Around(controllerPointcut()) public Object around(ProceedingJoinPoint pjp) throws Throwable { long start System.currentTimeMillis(); String methodName pjp.getSignature().toShortString(); log.info([AOP] 方法开始: {}, methodName); try { Object result pjp.proceed(); // 执行目标方法 long cost System.currentTimeMillis() - start; log.info([AOP] 方法结束: {}, 耗时 {}ms, methodName, cost); return result; } catch (Throwable e) { long cost System.currentTimeMillis() - start; log.error([AOP] 方法异常: {}, 耗时 {}ms, methodName, cost, e); throw e; } } /** * 前置通知 */ Before(controllerPointcut()) public void before() { // 在 Around 的 proceed() 之前执行 } }4.3 特点特点说明拦截范围任何 Spring Bean 的方法不限于 Controller能否获取方法参数可以JoinPoint.getArgs()能否修改参数可以Around 中修改 args 后 proceed能否修改返回值可以Around 中替换返回值能否中断执行可以Around 中不调用 proceed五、Listener监听器5.1 原理监听器是观察者模式的实现用于监听容器或应用中发生的事件。Spring Boot 中有两种监听器类型接口事件Servlet 监听器ServletRequestListener 等请求创建/销毁Spring 事件监听器ApplicationListener应用启动、刷新、自定义事件5.2 Servlet 请求监听器import jakarta.servlet.ServletRequestEvent; import jakarta.servlet.ServletRequestListener; import jakarta.servlet.annotation.WebListener; import org.springframework.stereotype.Component; /** * Servlet 请求监听器 */ Component public class RequestListener implements ServletRequestListener { Override public void requestInitialized(ServletRequestEvent sre) { System.out.println([Listener] 请求创建: sre.getServletRequest()); } Override public void requestDestroyed(ServletRequestEvent sre) { System.out.println([Listener] 请求销毁); } }5.3 Spring 事件监听器import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; /** * Spring 事件监听器 */ Component public class SpringEventListener { /** * 监听应用启动完成事件 */ EventListener public void onApplicationReady(ApplicationReadyEvent event) { System.out.println([Listener] 应用启动完成); } /** * 监听自定义事件 */ EventListener public void onOrderCreated(OrderCreatedEvent event) { System.out.println([Listener] 收到订单创建事件: event.getOrderId()); } }自定义事件import lombok.Getter; import org.springframework.context.ApplicationEvent; /** * 订单创建事件 */ Getter public class OrderCreatedEvent extends ApplicationEvent { private final String orderId; public OrderCreatedEvent(Object source, String orderId) { super(source); this.orderId orderId; } }发布事件import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; Service public class OrderService { private final ApplicationEventPublisher eventPublisher; public OrderService(ApplicationEventPublisher eventPublisher) { this.eventPublisher eventPublisher; } public void createOrder(String orderId) { // 业务逻辑... System.out.println(订单创建: orderId); // 发布事件 eventPublisher.publishEvent(new OrderCreatedEvent(this, orderId)); } }与 Filter/Interceptor 的区别Listener 是被动的事件回调不能拦截或中断请求流程。六、ControllerAdvice全局异常与数据绑定6.1 原理RestControllerAdvice/ControllerAdvice是 Spring MVC 提供的全局增强机制可以处理 Controller 层的异常、全局数据绑定、全局数据预处理。6.2 全局异常处理import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; /** * 全局异常处理器 */ Slf4j RestControllerAdvice public class GlobalExceptionHandler { /** * 处理业务异常 */ ExceptionHandler(BusinessException.class) ResponseStatus(HttpStatus.OK) public MapString, Object handleBusiness(BusinessException e) { log.warn(业务异常: {}, e.getMessage()); MapString, Object result new HashMap(); result.put(code, e.getCode()); result.put(message, e.getMessage()); return result; } /** * 处理参数校验异常 */ ExceptionHandler(IllegalArgumentException.class) ResponseStatus(HttpStatus.BAD_REQUEST) public MapString, Object handleIllegalArg(IllegalArgumentException e) { log.warn(参数异常: {}, e.getMessage()); MapString, Object result new HashMap(); result.put(code, 400); result.put(message, e.getMessage()); return result; } /** * 兜底处理所有未捕获异常 */ ExceptionHandler(Exception.class) ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public MapString, Object handleException(Exception e) { log.error(系统异常, e); MapString, Object result new HashMap(); result.put(code, 500); result.put(message, 系统繁忙); return result; } }6.3 全局数据绑定RestControllerAdvice public class GlobalDataBinder { InitBinder public void initBinder(WebDataBinder binder) { // 注册自定义编辑器 binder.registerCustomEditor(String.class, new StringTrimmerEditor(true)); } }6.4 全局数据预处理RestControllerAdvice public class GlobalRequestBodyAdvice { ModelAttribute public void addCommonAttributes(Model model) { model.addAttribute(serverTime, System.currentTimeMillis()); } }关键ExceptionHandler只能捕获 Controller 层抛出的异常不能捕获 Filter 层的异常。七、HandlerMethodArgumentResolver参数处理器7.1 原理参数处理器负责将 HTTP 请求中的数据解析为 Controller 方法的入参。Spring MVC 内置了多个处理器内置处理器处理的注解RequestParamMethodArgumentResolverRequestParamPathVariableMethodArgumentResolverPathVariableRequestBodyMethodArgumentResolverRequestBodyRequestHeaderMethodArgumentResolverRequestHeaderModelAttributeMethodProcessorModelAttribute当内置处理器不满足需求时可以自定义。7.2 自定义参数处理器示例场景从 Token 中解析当前登录用户直接注入 Controller 方法。import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import jakarta.servlet.http.HttpServletRequest; /** * 自定义参数处理器解析 CurrentUser 注解 */ Component public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver { Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(CurrentUser.class) parameter.getParameterType().equals(UserInfo.class); } Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request webRequest.getNativeRequest(HttpServletRequest.class); String token request.getHeader(Authorization); // 从 token 解析用户信息实际项目中通常从 JWT 或缓存中获取 UserInfo user parseToken(token); return user; } private UserInfo parseToken(String token) { UserInfo user new UserInfo(); user.setId(1001L); user.setName(张三); return user; } }自定义注解import java.lang.annotation.*; Target(ElementType.PARAMETER) Retention(RetentionPolicy.RUNTIME) Documented public interface CurrentUser { }用户信息类import lombok.Data; Data public class UserInfo { private Long id; private String name; }注册参数处理器import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; Configuration public class WebMvcConfig implements WebMvcConfigurer { private final CurrentUserArgumentResolver currentUserResolver; public WebMvcConfig(CurrentUserArgumentResolver currentUserResolver) { this.currentUserResolver currentUserResolver; } Override public void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) { resolvers.add(currentUserResolver); } }在 Controller 中使用RestController RequestMapping(/api/user) public class UserController { GetMapping(/profile) public MapString, Object getProfile(CurrentUser UserInfo user) { MapString, Object result new HashMap(); result.put(id, user.getId()); result.put(name, user.getName()); return result; } }八、HandlerMethodReturnValueHandler返回值处理器8.1 原理返回值处理器负责将 Controller 方法的返回值转换为 HTTP 响应。内置处理器包括内置处理器处理场景RequestResponseBodyMethodProcessorResponseBody / RestControllerModelAndViewMethodReturnValueHandler返回 ModelAndViewViewMethodReturnValueHandler返回 String视图名HttpEntityMethodProcessor返回 ResponseEntity8.2 自定义返回值处理器示例场景Controller 方法返回实体对象自动包装为统一响应格式ResultT。import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import java.util.HashMap; import java.util.Map; /** * 统一返回值包装 * p * 通过 ResponseBodyAdvice 实现它本质上是返回值处理器的增强钩子。 */ RestControllerAdvice public class GlobalResponseHandler implements ResponseBodyAdviceObject { Override public boolean supports(MethodParameter returnType, Class? extends HttpMessageConverter? converterType) { // 如果已经是 Result 类型则不再包装 return !returnType.getParameterType().equals(Result.class); } Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class? extends HttpMessageConverter? selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { MapString, Object result new HashMap(); result.put(code, 0); result.put(message, success); result.put(data, body); return result; } }统一响应类import lombok.Data; Data public class ResultT { private int code; private String message; private T data; public static T ResultT success(T data) { ResultT r new Result(); r.setCode(0); r.setMessage(success); r.setData(data); return r; } public static T ResultT fail(String message) { ResultT r new Result(); r.setCode(500); r.setMessage(message); return r; } }注意ResponseBodyAdvice不是完整的ReturnValueHandler而是在RequestResponseBodyMethodProcessor内部的增强钩子。完整自定义需要实现HandlerMethodReturnValueHandler接口并注册但实际项目中ResponseBodyAdvice已足够。九、横向对比9.1 执行顺序HTTP 请求到达 │ ├── 1. Listener.requestInitialized() ← Servlet 请求监听器 │ ├── 2. Filter.doFilter() [请求阶段] ← 过滤器 │ (Filter1 → Filter2 → ...) │ ├── 3. DispatcherServlet │ │ │ ├── 3.1 Interceptor.preHandle() ← 拦截器-前置 │ │ │ ├── 3.2 ArgumentResolver ← 参数处理器 │ │ │ ├── 3.3 AOP Around [前半段] ← AOP如果有 │ │ ├── AOP Before │ │ ├── Controller 方法执行 │ │ └── AOP AfterReturning / AfterThrowing │ │ └── AOP After │ │ └── AOP Around [后半段] │ │ │ ├── 3.4 ReturnValueHandler ← 返回值处理器 │ │ └── ResponseBodyAdvice │ │ │ ├── 3.5 Interceptor.postHandle() ← 拦截器-后置 │ │ │ └── 3.6 Interceptor.afterCompletion() ← 拦截器-完成 │ ├── 4. Filter.doFilter() [响应阶段] │ (... → Filter2 → Filter1) │ └── 5. Listener.requestDestroyed() ← Servlet 请求监听器 异常分支 Controller 抛出异常 → AOP AfterThrowing → Interceptor.afterCompletion() → RestControllerAdvice ExceptionHandler Filter 抛出异常 → 不会进入 ControllerAdvice需在 Filter 中自行处理核心记忆Filter → Interceptor.preHandle → ArgumentResolver → AOP → Controller → ReturnValueHandler → Interceptor.postHandle → Interceptor.afterCompletion → Filter9.2 功能对比矩阵能力FilterInterceptorAOPListenerControllerAdviceArgumentResolverReturnValueHandler拦截所有请求✅❌ 仅 Controller❌ 仅 Bean 方法✅❌❌❌拦截静态资源✅❌❌✅❌❌❌获取 Controller 方法信息❌✅✅❌✅✅✅获取方法参数值❌✅✅❌❌✅可修改❌修改方法参数❌❌✅❌❌✅❌修改返回值❌❌✅❌❌❌✅中断请求✅✅✅❌❌❌❌处理异常✅自行处理❌✅❌✅❌❌感知事务❌✅✅❌❌❌❌作用范围Servlet 容器Spring MVCSpring 容器Servlet/SpringSpring MVCSpring MVCSpring MVC9.3 适用场景对比场景推荐组件理由请求日志记录Filter能记录所有请求含静态资源且在最早阶段拦截登录鉴权Interceptor只需拦截 Controller 请求可获取 Handler 信息可排除特定路径权限校验Interceptor同上且可获取 Controller 注解接口耗时统计AOP可精确到方法级别可统计 Service 层耗时参数校验/签名AOP 或 InterceptorAOP 更灵活可作用于 Service 层Interceptor 更简单统一返回值包装ResponseBodyAdvice不侵入 Controller 代码自动包装所有返回值自定义参数注入ArgumentResolver如 CurrentUser 注入登录用户全局异常处理ControllerAdvice统一处理 Controller 异常避免 try-catch 散落各处跨域处理Filter 或 CorsFilter在最早阶段处理 CORS 预检请求请求体加密/解密Filter Wrapper需要在请求到达 Controller 前修改请求体事件通知Listener异步解耦如订单创建后发通知接口限流Filter 或 InterceptorFilter 更早拦截减少资源消耗9.4 功能交叉点分析交叉点一Filter vs Interceptor — 都能拦截请求相同点 - 都能在请求前后执行逻辑 - 都能中断请求 - 都能获取 HttpServletRequest / HttpServletResponse 不同点 - Filter 拦截所有请求含静态资源Interceptor 只拦截 Controller - Filter 不感知 Controller 信息Interceptor 可以获取 HandlerMethod - Filter 在 DispatcherServlet 外Interceptor 在内 - Interceptor 的 excludePathPatterns 配置更灵活 选型建议 - 需要拦截所有请求 → Filter如跨域、字符编码 - 只需拦截 Controller → Interceptor如登录校验、权限控制交叉点二Interceptor vs AOP — 都能拦截 Controller 方法相同点 - 都能在 Controller 方法前后执行逻辑 - 都能获取方法签名和参数 - 都能中断执行 不同点 - Interceptor 只能拦截 ControllerAOP 能拦截任何 Bean - Interceptor 有 postHandle视图渲染前AOP 没有 - AOP 更灵活Around 可控制是否执行、可修改参数和返回值 - Interceptor 更简单实现接口即可无需切点表达式 - AOP 基于动态代理同类内部方法调用不走代理自调用问题 选型建议 - 只需拦截 Controller、逻辑简单 → Interceptor - 需要拦截 Service 层、需要修改参数或返回值 → AOP交叉点三ControllerAdvice vs Interceptor — 都能处理异常相同点 - 都在 Spring MVC 层面工作 不同点 - ControllerAdvice 专门处理异常Interceptor 的 afterCompletion 只能感知异常但不能处理 - ControllerAdvice 可以针对不同异常类型返回不同响应 - Interceptor 无法修改异常的走向异常会继续传播 选型建议 - 异常处理 → 始终用 ControllerAdvice交叉点四Filter vs Interceptor — 都能做日志记录Filter 做日志 能记录所有请求含 404、静态资源 能获取最终响应状态码 - 不能获取 Controller 类名和方法名 Interceptor 做日志 能获取 Controller 类名和方法名 可以排除不需要记录的路径 - 不能记录非 Controller 请求如 404 选型建议 - 访问日志access log→ Filter - 接口调用日志需要方法名→ Interceptor 或 AOP十、实战组合使用示例一个典型的 Spring Boot 项目通常同时使用多种组件import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; /** * Web MVC 统一配置 */ Configuration public class WebMvcConfig implements WebMvcConfigurer { private final LoginInterceptor loginInterceptor; private final CurrentUserArgumentResolver currentUserResolver; public WebMvcConfig(LoginInterceptor loginInterceptor, CurrentUserArgumentResolver currentUserResolver) { this.loginInterceptor loginInterceptor; this.currentUserResolver currentUserResolver; } Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns(/api/**) .excludePathPatterns(/api/login, /api/register); } Override public void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) { resolvers.add(currentUserResolver); } }各组件分工组件职责Filter请求日志、跨域处理、字符编码Interceptor登录校验、权限控制AOP接口耗时统计、操作日志ControllerAdvice全局异常处理ArgumentResolverCurrentUser 注入登录用户ResponseBodyAdvice统一返回值包装Listener应用启动初始化、订单事件通知Controller 代码保持极简RestController RequestMapping(/api/order) public class OrderController { private final OrderService orderService; public OrderController(OrderService orderService) { this.orderService orderService; } PostMapping(/create) public OrderVO createOrder(CurrentUser UserInfo user, RequestBody Valid OrderCreateRequest request) { return orderService.createOrder(user.getId(), request); } }执行流程1. Filter → 记录请求日志 2. Interceptor → 校验登录 token 3. ArgumentResolver → 解析 token注入 UserInfo 4. AOP Around → 开始计时 5. Controller → 执行业务逻辑 6. AOP Around → 结束计时记录日志 7. ResponseBodyAdvice → 包装返回值为 {code, message, data} 8. Interceptor.afterCompletion → 清理资源 9. Filter → 记录响应日志十一、常见误区与最佳实践11.1 常见误区误区正解Filter 中抛异常会被 ControllerAdvice 捕获❌ 不会。Filter 在 DispatcherServlet 之外需要自行 try-catchInterceptor 的 postHandle 在异常时也会执行❌ Controller 抛异常时 postHandle 不执行只有 afterCompletion 执行AOP 可以拦截同类内部方法调用❌ this.method() 不走代理只有外部调用才走代理Listener 可以中断请求❌ Listener 是事件回调不能中断流程ResponseBodyAdvice 对所有返回值生效❌ 只对 ResponseBody / RestController 的方法生效多个 Interceptor 的 postHandle 按注册顺序执行❌ postHandle 和 afterCompletion 按注册的逆序执行11.2 多个拦截器的执行顺序拦截器注册顺序A → B → C preHandle 执行顺序A → B → C正序 postHandle 执行顺序C → B → A逆序 afterCompletion 执行顺序C → B → A逆序 如果 B 的 preHandle 返回 false A.preHandle ✅ B.preHandle ❌返回 false C.preHandle 不执行 Controller 不执行 postHandle 都不执行 afterCompletionA.afterCompletion ✅已 preHandle 成功的会执行 C.afterCompletion 不执行11.3 最佳实践职责单一每个组件只做一件事不要在 Filter 中做业务逻辑异常处理分层Filter 异常自行处理Controller 异常交给 ControllerAdvice避免循环依赖Filter 中注入 Bean 时注意 Bean 的初始化时机拦截器路径配置用excludePathPatterns排除登录、注册等公开接口AOP 自调用问题同类方法内部调用不走代理需要通过AopContext.currentProxy()或拆分到不同类参数处理器优先级自定义 ArgumentResolver 添加到列表末尾避免覆盖内置处理器ResponseBodyAdvice 判断类型在supports()中排除已是 Result 类型的返回值避免重复包装十二、总结12.1 选型决策树需要在请求最外层拦截 ├── 是 → Filter │ 跨域、编码、访问日志 └── 否 → 需要拦截 Controller 方法 ├── 是 → 需要修改参数或返回值 │ ├── 是 → AOP │ │ 耗时统计、参数处理 │ └── 否 → 需要获取 Handler 信息 │ ├── 是 → Interceptor │ │ 登录校验、权限控制 │ └── 否 → AOP 或 Interceptor 均可 └── 否 → 需要处理异常 ├── 是 → ControllerAdvice │ 全局异常处理 └── 否 → 需要自定义参数注入 ├── 是 → ArgumentResolver │ CurrentUser └── 否 → 需要统一包装返回值 ├── 是 → ResponseBodyAdvice └── 否 → 需要监听事件 └── Listener12.2 核心要点速查Filter在 DispatcherServlet 外拦截所有请求适合跨域、编码、访问日志Interceptor在 DispatcherServlet 内只拦截 Controller适合登录鉴权、权限控制AOP基于 Spring 动态代理能拦截任何 Bean 方法适合耗时统计、操作日志Listener是事件回调不能中断请求适合应用初始化、事件通知ControllerAdvice专门处理 Controller 层异常不能捕获 Filter 层异常ArgumentResolver自定义参数解析如CurrentUser注入登录用户ResponseBodyAdvice统一包装返回值不侵入 Controller 代码执行顺序Filter → Interceptor.preHandle → ArgumentResolver → AOP → Controller → ReturnValueHandler → Interceptor.postHandle → afterCompletion → FilterInterceptor 的 postHandle 和 afterCompletion 按注册逆序执行AOP 自调用不走代理需通过AopContext.currentProxy()解决