拦截器与过滤器扩展机制
拦截器(Interceptor)和过滤器(Filter)是Web请求处理的两个重要扩展点,执行时机和作用范围不同。
拦截器与过滤器对比
| 特性 | 拦截器(Interceptor) | 过滤器(Filter) |
|---|---|---|
| 所属 | SpringMVC | Servlet容器 |
| 执行时机 | DispatcherServlet内 | DispatcherServlet外 |
| 拦截范围 | Controller请求 | 所有请求(含静态资源) |
| 获取Bean | 可访问Spring容器 | 无法访问Spring容器 |
| 异常处理 | 可被HandlerExceptionResolver处理 | 需自行处理 |
执行顺序图
Java
请求 → Filter1.doFilter前置
→ Filter2.doFilter前置
→ DispatcherServlet
→ Interceptor1.preHandle
→ Interceptor2.preHandle
→ Handler执行
→ Interceptor2.postHandle
→ Interceptor1.postHandle
→ 视图渲染
→ Interceptor2.afterCompletion
→ Interceptor1.afterCompletion
→ Filter2.doFilter后置
→ Filter1.doFilter后置
→ 响应
拦截器实现
HandlerInterceptor接口
Java
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
return true;
}
default void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) {
}
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler,
Exception ex) {
}
}
自定义拦截器
Java
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
String token = request.getHeader("Authorization");
if (token == null || !validateToken(token)) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType("application/json");
response.getWriter().write("{\"error\":\"未授权\"}");
return false;
}
// 设置用户信息到请求属性
User user = getUserFromToken(token);
request.setAttribute("currentUser", user);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
// 清理资源
request.removeAttribute("currentUser");
}
}
注册拦截器
Java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor())
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**")
.order(1);
registry.addInterceptor(new LogInterceptor())
.addPathPatterns("/**")
.order(2);
registry.addInterceptor(new CacheInterceptor())
.addPathPatterns("/api/data/**")
.order(3);
}
}
AsyncHandlerInterceptor
Java
// 异步请求拦截器扩展
public interface AsyncHandlerInterceptor extends HandlerInterceptor {
default void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response, Object handler) {
// 异步处理开始时调用
}
}
过滤器实现
Filter接口
Java
public interface Filter {
void init(FilterConfig filterConfig);
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain);
void destroy();
}
自定义过滤器
Java
@Component
@Order(1)
public class RequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
long startTime = System.currentTimeMillis();
// 前置处理
log.info("请求开始: {} {}", httpRequest.getMethod(), httpRequest.getRequestURI());
try {
chain.doFilter(request, response);
} finally {
// 后置处理
long duration = System.currentTimeMillis() - startTime;
log.info("请求结束: {} {} 耗时{}ms",
httpRequest.getMethod(), httpRequest.getRequestURI(), duration);
}
}
}
注册过滤器
Java
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<RequestLoggingFilter> loggingFilter() {
FilterRegistrationBean<RequestLoggingFilter> registration =
new FilterRegistrationBean<>();
registration.setFilter(new RequestLoggingFilter());
registration.addUrlPatterns("/*");
registration.setName("requestLoggingFilter");
registration.setOrder(1);
return registration;
}
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
FilterRegistrationBean<CorsFilter> registration =
new FilterRegistrationBean<>();
registration.setFilter(new CorsFilter());
registration.addUrlPatterns("/*");
registration.setName("corsFilter");
registration.setOrder(0); // CORS优先级最高
return registration;
}
}
DelegatingFilterProxy
Java
// 将Servlet过滤器代理到Spring Bean
@Configuration
public class SecurityConfig {
@Bean
public FilterRegistrationBean<DelegatingFilterProxy> securityFilter() {
FilterRegistrationBean<DelegatingFilterProxy> registration =
new FilterRegistrationBean<>();
registration.setFilter(new DelegatingFilterProxy("springSecurityFilterChain"));
registration.addUrlPatterns("/*");
registration.setName("springSecurityFilterChain");
return registration;
}
}
OncePerRequestFilter
Java
// 确保每个请求只执行一次
@Component
public class CorsFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.setHeader("Access-Control-Allow-Headers", "*");
response.setHeader("Access-Control-Max-Age", "3600");
if ("OPTIONS".equals(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return;
}
filterChain.doFilter(request, response);
}
}
拦截器链执行源码
Java
// HandlerExecutionChain
public class HandlerExecutionChain {
private int interceptorIndex = -1;
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) {
for (int i = 0; i < this.interceptorList.size(); i++) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
return true;
}
void applyPostHandle(HttpServletRequest request, HttpServletResponse response,
ModelAndView modelAndView) {
for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.postHandle(request, response, this.handler, modelAndView);
}
}
void triggerAfterCompletion(HttpServletRequest request,
HttpServletResponse response, Exception ex) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = this.interceptorList.get(i);
interceptor.afterCompletion(request, response, this.handler, ex);
}
}
}
过滤器链执行源码
Java
// ApplicationFilterChain
public final class ApplicationFilterChain implements FilterChain {
private int pos = 0;
private int n = 0;
private Filter[] filters;
public void doFilter(ServletRequest request, ServletResponse response) {
if (pos < n) {
Filter filter = filters[pos++];
filter.doFilter(request, response, this);
} else {
// 所有过滤器执行完毕,调用Servlet
servlet.service(request, response);
}
}
}
异步请求处理
Java
@Component
public class AsyncInterceptor implements AsyncHandlerInterceptor {
@Override
public void afterConcurrentHandlingStarted(HttpServletRequest request,
HttpServletResponse response, Object handler) {
log.info("异步处理开始: {}", request.getRequestURI());
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
log.info("异步处理完成: {}", request.getRequestURI());
}
}
// Controller异步处理
@GetMapping("/async")
public Callable<String> asyncProcess() {
return () -> {
Thread.sleep(1000);
return "result";
};
}
拦截器获取Spring Bean
text
@Component
public class ServiceInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService; // 可注入Spring Bean
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) {
User user = userService.getCurrentUser();
request.setAttribute("user", user);
return true;
}
}
拦截器可注入Spring Bean,过滤器需要通过DelegatingFilterProxy代理或ServletContext获取。
要点总结
- 过滤器在Servlet容器级别,拦截器在SpringMVC容器级别
- 过滤器可拦截所有请求,拦截器只拦截Controller请求
- 拦截器可访问Spring容器Bean,过滤器无法直接访问
- 拦截器preHandle返回false终止链条
- OncePerRequestFilter确保异步请求只执行一次
jwdev/articles/SPRINGMVC/专家/容器级WEB组件扩展/容器级WEB组件扩展/拦截器与过滤器扩展机制.md
📝 发现内容有误?点击此处直接编辑