Spring 拦截器链(Interceptor Chain)完整示例
核心目标
展示 多个 Interceptor 组成拦截器链的完整实现,包含 preHandle()
、postHandle()
、afterCompletion()
全生命周期方法,以及如何通过 WebMvcConfigurer
控制执行顺序。最后用表格总结拦截器生命周期。
代码结构
- 拦截器 1:记录请求时间(
TimingInterceptor
)。 - 拦截器 2:权限验证(
AuthInterceptor
)。 - 拦截器链配置:通过
WebMvcConfigurer
控制顺序。 - 测试 Controller:验证拦截器链执行流程。
完整代码示例
1. 拦截器 1:记录请求时间
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class TimingInterceptor implements HandlerInterceptor {private long startTime; // 记录请求开始时间// **前置处理(preHandle)**@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {startTime = System.currentTimeMillis();System.out.println("TimingInterceptor 前置处理开始");return true; // 返回 true 继续处理,false 中断请求}// **后置处理(postHandle)**@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {long endTime = System.currentTimeMillis();System.out.println("TimingInterceptor 后置处理,总耗时:" + (endTime - startTime) + "ms");}// **完成处理(afterCompletion)**@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {System.out.println("TimingInterceptor 完成处理(请求结束)");}
}
2. 拦截器 2:权限验证
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class AuthInterceptor implements HandlerInterceptor {// **前置处理(preHandle)**@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String token = request.getHeader("Authorization");if (token == null || !token.equals("valid_token")) {System.out.println("权限验证失败,拒绝访问");response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);return false; // 中断请求}System.out.println("权限验证通过");return true;}// **后置处理(postHandle)**@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {System.out.println("AuthInterceptor 后置处理(Controller 执行后)");}// **完成处理(afterCompletion)**@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {System.out.println("AuthInterceptor 完成处理(请求完全结束)");}
}
3. 拦截器链配置类
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 {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册 TimingInterceptor(顺序1)registry.addInterceptor(new TimingInterceptor()).order(1) // 优先级最高(数值越小优先级越高).addPathPatterns("/**"); // 拦截所有路径// 注册 AuthInterceptor(顺序2)registry.addInterceptor(new AuthInterceptor()).order(2) // 优先级次之.addPathPatterns("/**").excludePathPatterns("/login"); // 排除登录接口}
}
4. 测试 Controller
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class TestController {@GetMapping("/test")public String test() {System.out.println("Controller 方法执行");return "Hello from Controller!";}@GetMapping("/login")public String login() {return "登录成功";}
}
5. 启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
执行流程与输出结果
访问 /test
接口(假设请求头包含 Authorization: valid_token
),控制台输出如下:
TimingInterceptor 前置处理开始
权限验证通过
AuthInterceptor 后置处理(Controller 执行后)
TimingInterceptor 后置处理,总耗时:Xms
AuthInterceptor 完成处理(请求完全结束)
TimingInterceptor 完成处理(请求结束)
Controller 方法执行
拦截器生命周期总结表格
方法 | 执行时机 | 作用 |
---|---|---|
preHandle() | 在 Controller 方法执行前调用。 | 预处理请求(如权限校验、日志记录),返回 false 可中断请求流程。 |
postHandle() | 在 Controller 方法执行后,视图渲染前调用。 | 后置处理(如修改响应数据、记录日志),不影响请求流程。 |
afterCompletion() | 在 请求完全处理后调用(包括视图渲染完成或发生异常)。 | 最终清理操作(如释放资源、记录请求结束状态)。 |
关键点说明
-
拦截器链顺序控制:
- 通过
InterceptorRegistry.order()
设置优先级(数值越小优先级越高)。 preHandle()
方法按order
顺序执行,postHandle()
和afterCompletion()
按逆序执行。
- 通过
-
生命周期阶段对比:
preHandle()
:决定是否继续请求流程。postHandle()
:修改响应数据(如添加公共字段)。afterCompletion()
:资源释放(如关闭数据库连接)。
-
典型应用场景:
preHandle()
:权限校验、请求参数校验。postHandle()
:统一返回格式封装、日志记录。afterCompletion()
:性能监控、异常统计。
常见问题
-
如何动态调整拦截器顺序?
- 修改
order()
的数值,无需重启应用即可生效。
- 修改
-
preHandle()
返回false
后如何处理?- 请求立即终止,后续拦截器和 Controller 不会执行,需在
preHandle()
中设置响应状态码(如401
)。
- 请求立即终止,后续拦截器和 Controller 不会执行,需在
-
afterCompletion()
是否在异常时执行?- 是的,无论请求是否成功,
afterCompletion()
都会执行,可通过Exception ex
参数获取异常信息。
- 是的,无论请求是否成功,
执行流程图
请求到达 →
├─ TimingInterceptor.preHandle() →
│ ├─ 返回 true → 继续链 →
│ ├─ AuthInterceptor.preHandle() →
│ │ ├─ 返回 true → 执行 Controller →
│ │ └─ AuthInterceptor.postHandle() →
│ └─ TimingInterceptor.postHandle() →
└─ 返回响应 →├─ AuthInterceptor.afterCompletion() →└─ TimingInterceptor.afterCompletion()