这是一个非常经典且重要的 Java Web 开发问题。下面从作用机制、执行时机、依赖环境、注册方式 等多个维度,清晰解释 拦截器(Interceptor) 与 过滤器(Filter) 的区别,并回答你关于"是否需要注册"的问题。
✅ 一、核心区别总览
| 特性 | 过滤器(Filter) | 拦截器(Interceptor) |
|---|---|---|
| 所属规范 | Servlet 规范(Java EE) | Spring MVC / Spring Boot 框架 |
| 依赖容器 | Servlet 容器(如 Tomcat) | Spring IoC 容器 |
| 作用范围 | 所有 Web 资源(Servlet、JSP、HTML、图片等) | 仅 Spring MVC 的 Controller 请求 |
| 执行时机 | 在 DispatcherServlet 之前 |
在 DispatcherServlet 之后,Controller 之前/后 |
| 能否注入 Spring Bean | ❌ 不能直接注入(需手动获取) | ✅ 可直接 @Autowired |
| 执行顺序 | Filter → DispatcherServlet → Interceptor → Controller |
📌 关键记忆点 :
Filter 是"外层守门员",Interceptor 是"Spring 内部管家"
🔍 二、详细对比说明
1. 作用阶段不同
- Filter :
工作在 Servlet 容器层面 ,请求一进来就触发,连静态资源(如/js/app.js)也能拦截。 - Interceptor :
工作在 Spring MVC 流程中 ,只有经过DispatcherServlet分发的请求(即映射到@Controller的请求)才会被拦截。
💡 举例:
访问
http://localhost:8080/logo.png
- Filter 会执行 ✅
- Interceptor 不会执行 ❌
2. 对 Spring 生态的支持
-
Filter :
不属于 Spring 管理,无法直接使用@Service、@Repository等 Bean。
若需使用,必须通过:WebApplicationContextUtils.getWebApplicationContext(servletContext) .getBean(UserService.class); -
Interceptor :
是 Spring Bean,可直接注入:@Component public class AuthInterceptor implements HandlerInterceptor { @Autowired private UserService userService; // 直接注入 ✅ }
3. 方法粒度控制
- Filter :只能按 URL 模式匹配(如
/*,/api/*),无法精确到某个 Controller 方法。 - Interceptor :可通过
addPathPatterns()和excludePathPatterns()精细控制,甚至结合注解实现方法级拦截。
✅ 三、是否需要注册?
▶ 过滤器(Filter)------ 必须注册!
否则 Servlet 容器不知道它的存在。
注册方式(任选其一):
-
注解方式(Servlet 3.0+)
@WebFilter(urlPatterns = "/*") public class LogFilter implements Filter { ... }⚠️ 需在主启动类加
@ServletComponentScan -
配置类方式(推荐,尤其 Spring Boot)
@Configuration public class FilterConfig { @Bean public FilterRegistrationBean<LogFilter> logFilter() { FilterRegistrationBean<LogFilter> bean = new FilterRegistrationBean<>(); bean.setFilter(new LogFilter()); bean.addUrlPatterns("/*"); return bean; } }
▶ 拦截器(Interceptor)------ 必须注册!
Spring 不会自动发现你实现的 HandlerInterceptor。
注册方式(唯一标准方式):
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/login");
}
}
❌ 如果不注册,即使加了
@Component,也不会生效!
推荐】结构化写法:定义与注册分离(适合大型项目)
将 组件定义 和 注册逻辑 完全解耦,代码更清晰、易测试、易维护。
1. 定义 Filter
java
编辑
// src/main/java/com/example/filter/LogFilter.java
@Component
public class LogFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
long start = System.currentTimeMillis();
chain.doFilter(request, response);
System.out.println("请求耗时: " + (System.currentTimeMillis() - start) + "ms");
}
}
2. 定义 Interceptor
java
编辑
// src/main/java/com/example/interceptor/AuthInterceptor.java
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 鉴权逻辑
return true;
}
}
3. 统一注册配置类
// src/main/java/com/example/config/WebConfig.java
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final LogFilter logFilter;
private final AuthInterceptor authInterceptor;
public WebConfig(LogFilter logFilter, AuthInterceptor authInterceptor) {
this.logFilter = logFilter;
this.authInterceptor = authInterceptor;
}
// 注册 Filter
@Bean
public FilterRegistrationBean<LogFilter> logFilterRegistration() {
FilterRegistrationBean<LogFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(logFilter);
registration.addUrlPatterns("/*");
registration.setOrder(1);
return registration;
}
// 注册 Interceptor
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**");
}
}
✅ 优点:
- 职责分离:Filter/Interceptor 只关注逻辑,配置类只关注注册
- 支持单元测试(可单独测试
AuthInterceptor)- 易于扩展(新增拦截器只需加一行注册)
🧪 四、执行顺序图示
客户端请求
↓
[ Filter 1 ] → doFilter()
↓
[ Filter 2 ] → doFilter()
↓
DispatcherServlet(Spring MVC 入口)
↓
[ Interceptor.preHandle() ]
↓
Controller 方法执行
↓
[ Interceptor.postHandle() ]
↓
视图渲染
↓
[ Interceptor.afterCompletion() ]
↓
[ Filter 2 ] → chain.doFilter() 之后的代码
↓
[ Filter 1 ] → chain.doFilter() 之后的代码
↓
响应返回客户端
🔥 注意:Filter 的
doFilter()中chain.doFilter()之前 是请求预处理,之后是响应后处理。
✅ 五、如何选择?
| 场景 | 推荐 |
|---|---|
设置全局字符编码(request.setCharacterEncoding("UTF-8")) |
✅ Filter(必须在 DispatcherServlet 前) |
| 拦截静态资源(如防盗链) | ✅ Filter |
| 登录校验、权限控制、日志记录(针对 API) | ✅ Interceptor(可注入 Service) |
| 全局 CORS、安全头(如 XSS 防护) | ✅ Filter |
需要修改 ModelAndView 或捕获 Controller 异常 |
✅ Interceptor |
✅ 总结
| 问题 | 答案 |
|---|---|
| 拦截器需要注册吗? | ✅ 需要!通过 WebMvcConfigurer.addInterceptors() |
| 过滤器需要注册吗? | ✅ 需要!通过 @WebFilter + @ServletComponentScan 或 FilterRegistrationBean |
| 谁先执行? | Filter 先于 Interceptor |
| 能互相替代吗? | ❌ 不能!作用层级不同,应根据场景选择 |
💡 最佳实践:
- 底层通用处理(编码、安全、静态资源)→ 用 Filter
- 业务逻辑相关(鉴权、日志、参数处理)→ 用 Interceptor
理解这一点,你就掌握了 Spring Web 请求处理的核心流程!