注:在 Spring Boot 项目中,Filter 和 Interceptor 都是常用于处理 HTTP 请求的机制,但它们的执行顺序有所不同。理解它们的执行顺序非常重要,特别是当你有一个用来生成 requestId 的过滤器和一个用来获取 requestId 的拦截器时。
两者的执行顺序分析
-
Filter:在 Servlet 容器级别工作,负责请求进入 Spring 框架之前的处理。过滤器是基于 Servlet 规范实现的,它在请求进入 Spring MVC 控制器之前就被执行。
-
Interceptor:在 Spring MVC 框架中工作,它是在请求进入 Spring 的控制器之前(即业务逻辑执行之前)和响应返回客户端之前执行的。拦截器是 Spring 提供的机制,适用于 Spring MVC 控制器的处理。
总结
- Filter 会在 Interceptor 之前执行;
- Filter 先对请求进行处理,可以修改请求对象、设置响应头或进行其他操作;
- Interceptor 会在请求进入 Spring 控制器之前执行,通常是用于业务逻辑层的处理或某些操作,如记录日志、权限校验等。
结合Controller 的顺序图解
- 请求到达服务器
→ Filter 处理请求 → Interceptor 处理请求 → Controller 处理请求 - 响应返回客户端
→ Interceptor 处理响应 → Filter 处理响应
代码实例
假设有一个 RequestIdFilter 过滤器来生成 requestId,同时有一个 RequestIdInterceptor 拦截器来获取 requestId。
- RequestIdFilter 过滤器
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.UUID;
public class RequestIdFilter implements Filter {
private static final String REQUEST_ID_HEADER = "X-Request-Id";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化过滤器
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 获取请求头中的 requestId,如果没有则生成新的 requestId
String requestId = httpRequest.getHeader(REQUEST_ID_HEADER);
if (requestId == null || requestId.isEmpty()) {
requestId = UUID.randomUUID().toString(); // 使用 UUID 生成唯一的 requestId
}
// 将 requestId 设置到请求上下文中
httpRequest.setAttribute(REQUEST_ID_HEADER, requestId);
// 设置到响应头中,返回给客户端
httpResponse.setHeader(REQUEST_ID_HEADER, requestId);
// 继续处理请求
chain.doFilter(request, response);
}
@Override
public void destroy() {
// 销毁过滤器
}
}
- RequestIdInterceptor 拦截器
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RequestIdInterceptor implements HandlerInterceptor {
private static final String REQUEST_ID_HEADER = "X-Request-Id";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取过滤器设置的 requestId
String requestId = (String) request.getAttribute(REQUEST_ID_HEADER);
if (requestId != null) {
// 在日志或者其他地方使用 requestId
System.out.println("RequestId in Interceptor: " + requestId);
}
return true; // 继续执行后续操作
}
}
- 注册 Filter:使用 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 FilterRegistrationBean<RequestIdFilter> loggingFilter() {
FilterRegistrationBean<RequestIdFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new RequestIdFilter());
registrationBean.addUrlPatterns("/api/*"); // 只拦截 /api/* 路径
return registrationBean;
}
}
- 注册 Interceptor:使用 WebMvcConfigurer 注册拦截器
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 {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册 RequestIdInterceptor 拦截器,拦截所有请求
registry.addInterceptor(new RequestIdInterceptor())
.addPathPatterns("/**");
}
}
小结
Filter 和 Interceptor 执行顺序是:Filter 先执行,Interceptor 后执行。
过滤器通常用于请求的预处理和响应的后处理,拦截器则更多用于业务逻辑层的拦截,例如验证、日志记录等。