在Java Web开发中,过滤器(Filter) 和 拦截器(Interceptor) 是两种重要的请求处理机制。它们都能够对HTTP请求进行预处理和后处理,但在实现方式、执行时机和应用场景上有着显著的区别。
特征 | 过滤器 (Filter) | 拦截器 (Interceptor) |
---|---|---|
️ 基于 | Servlet规范 | Spring框架 |
⚡ 执行时机 | Servlet容器级别 | Spring MVC级别 |
作用域 | 所有Web请求 | Spring管理的请求 |
配置方式 | web.xml 或 @WebFilter | Spring配置 |
依赖注入 | 不支持 | 完全支持 |
异常处理 | 有限 | 丰富 |
过滤器是基于Servlet规范的组件,运行在Servlet容器中,能够拦截所有进入应用的HTTP请求和响应。
public interface Filter {
// 初始化方法,容器启动时调用
default void init(FilterConfig filterConfig) throws ServletException {}
// 核心过滤方法,每次请求时调用
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
// 销毁方法,容器关闭时调用
default void destroy() {}
}
init()
方法doFilter()
方法destroy()
方法拦截器是Spring框架提供的机制,专门用于拦截进入Spring MVC的请求,提供更细粒度的控制。
public interface HandlerInterceptor {
// 前置处理:Controller执行前调用
default boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return true;
}
// 后置处理:Controller执行后,视图渲染前调用
default void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {}
// 完成处理:视图渲染完成后调用
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {}
}
下图展示了请求处理过程中各组件的交互时序:
下图展示了过滤器和拦截器在时间轴上的生命周期对比:
@WebFilter(urlPatterns = "/*", filterName = "encodingFilter")
@Order(1)
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 前置处理
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
System.out.println(" 编码过滤器 - 前置处理");
// 继续执行链
chain.doFilter(request, response);
// 后置处理
System.out.println(" 编码过滤器 - 后置处理");
}
}
@WebFilter(urlPatterns = "/admin/*", filterName = "authFilter")
@Order(2)
public class AuthenticationFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 检查用户是否已登录
String token = httpRequest.getHeader("Authorization");
if (token == null || !validateToken(token)) {
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.getWriter().write("❌ 未授权访问");
return; // 不继续执行链
}
System.out.println(" 权限验证通过");
// 继续执行
chain.doFilter(request, response);
}
private boolean validateToken(String token) {
// 实际的token验证逻辑
return "valid-token".equals(token);
}
}
@WebFilter(urlPatterns = "/*", filterName = "corsFilter")
@Order(0)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 设置CORS头
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS");
httpResponse.setHeader("Access-Control-Allow-Headers",
"Content-Type, Authorization");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
// 处理预检请求
if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(request, response);
}
}
@Component
public class LoggingInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
logger.info(" 请求开始 - URL: {}, Method: {}, 时间: {}",
request.getRequestURL(),
request.getMethod(),
new Date());
return true; // 继续执行
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
logger.info(" Controller执行完成 - Handler: {}", handler);
// 可以修改ModelAndView
if (modelAndView != null) {
modelAndView.addObject("requestTime", new Date());
}
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
logger.info("✅ 请求完成 - 执行时间: {}ms, 状态码: {}",
executeTime,
response.getStatus());
if (ex != null) {
logger.error("❌ 请求异常: ", ex);
}
// 清理资源
request.removeAttribute("startTime");
}
}
@Component
public class BusinessInterceptor implements HandlerInterceptor {
@Autowired
private UserService userService;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// 检查是否为HandlerMethod
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 检查是否需要权限验证
RequireAuth requireAuth = handlerMethod.getMethodAnnotation(RequireAuth.class);
if (requireAuth == null) {
return true;
}
// 从请求中获取用户信息
String userId = request.getHeader("User-Id");
if (userId == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("❌ 缺少用户信息");
return false;
}
// 检查用户是否在缓存中
String cacheKey = "user:" + userId;
User user = (User) redisTemplate.opsForValue().get(cacheKey);
if (user == null) {
// 从数据库查询用户
user = userService.findById(userId);
if (user == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("❌ 用户不存在");
return false;
}
// 缓存用户信息
redisTemplate.opsForValue().set(cacheKey, user, Duration.ofHours(1));
}
// 验证用户权限
if (!user.hasPermission(requireAuth.value())) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("❌ 权限不足");
return false;
}
// 将用户信息存储到请求中
request.setAttribute("currentUser", user);
logger.info("✅ 用户权限验证通过 - 用户: {}, 权限: {}",
user.getUsername(), requireAuth.value());
return true;
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequireAuth {
String value() default ""; // 所需权限
boolean admin() default false; // 是否需要管理员权限
}
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoggingInterceptor loggingInterceptor;
@Autowired
private BusinessInterceptor businessInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册日志拦截器,拦截所有请求
registry.addInterceptor(loggingInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/static/**", "/error")
.order(1);
// 注册业务拦截器,只拦截API请求
registry.addInterceptor(businessInterceptor)
.addPathPatterns("/api/**")
.excludePathPatterns("/api/public/**", "/api/login")
.order(2);
}
// 启用过滤器组件扫描
@Bean
public FilterRegistrationBean<EncodingFilter> encodingFilter() {
FilterRegistrationBean<EncodingFilter> registrationBean =
new FilterRegistrationBean<>();
registrationBean.setFilter(new EncodingFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
registrationBean.setName("encodingFilter");
return registrationBean;
}
}
场景 | 过滤器 | 拦截器 | 推荐选择 |
---|---|---|---|
字符编码 | ✅ | ❌ | Filter |
用户登录验证 | ⚠️ | ✅ | Interceptor |
权限控制 | ⚠️ | ✅ | Interceptor |
静态资源处理 | ✅ | ❌ | Filter |
跨域处理 | ✅ | ✅ | Filter |
业务日志 | ❌ | ✅ | Interceptor |
性能监控 | ✅ | ✅ | 都可以 |
// 选择决策树
if (需要处理静态资源) {
return "使用Filter";
} else if (需要Spring依赖注入) {
return "使用Interceptor";
} else if (需要在多个时机处理) {
return "使用Interceptor";
} else if (是底层通用功能) {
return "使用Filter";
} else {
return "使用Interceptor";
}
// ❌ 避免在过滤器中进行重量级操作
@WebFilter("/*")
public class BadFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 避免:数据库查询、复杂计算、网络调用
User user = userService.complexQuery(); // 性能瓶颈
chain.doFilter(request, response);
}
}
// ✅ 正确:轻量级处理
@WebFilter("/*")
public class GoodFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 推荐:简单的处理逻辑
request.setCharacterEncoding("UTF-8");
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
try {
chain.doFilter(request, response);
} finally {
// 清理工作
long duration = System.currentTimeMillis() - startTime;
if (duration > 1000) { // 超过1秒记录日志
logger.warn("慢请求: {} - {}ms",
((HttpServletRequest) request).getRequestURI(),
duration);
}
}
}
}
@Component
public class SafeInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(SafeInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
try {
// 业务逻辑
return validateRequest(request);
} catch (BusinessException e) {
logger.error("业务异常: {}", e.getMessage());
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write(e.getMessage());
return false;
} catch (Exception e) {
logger.error("系统异常", e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write("系统繁忙,请稍后重试");
return false;
}
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
try {
// 清理资源
cleanupResources(request);
} catch (Exception e) {
logger.error("资源清理失败", e);
}
}
private void cleanupResources(HttpServletRequest request) {
// 清理请求中的临时数据
request.removeAttribute("tempData");
request.removeAttribute("startTime");
}
}
@Configuration
@EnableConfigurationProperties(WebFilterProperties.class)
public class FilterConfig {
@Autowired
private WebFilterProperties properties;
@Bean
@ConditionalOnProperty(name = "app.filter.encoding.enabled", havingValue = "true")
public FilterRegistrationBean<EncodingFilter> encodingFilter() {
FilterRegistrationBean<EncodingFilter> registrationBean =
new FilterRegistrationBean<>();
registrationBean.setFilter(new EncodingFilter());
registrationBean.addUrlPatterns(properties.getEncoding().getUrlPatterns());
registrationBean.setOrder(properties.getEncoding().getOrder());
return registrationBean;
}
@Bean
@ConditionalOnProperty(name = "app.filter.cors.enabled", havingValue = "true")
public FilterRegistrationBean<CorsFilter> corsFilter() {
FilterRegistrationBean<CorsFilter> registrationBean =
new FilterRegistrationBean<>();
registrationBean.setFilter(new CorsFilter());
registrationBean.addUrlPatterns(properties.getCors().getUrlPatterns());
registrationBean.setOrder(properties.getCors().getOrder());
return registrationBean;
}
}
@ConfigurationProperties(prefix = "app.filter")
@Data
public class WebFilterProperties {
private EncodingProperties encoding = new EncodingProperties();
private CorsProperties cors = new CorsProperties();
@Data
public static class EncodingProperties {
private boolean enabled = true;
private String[] urlPatterns = {"/*"};
private int order = 1;
}
@Data
public static class CorsProperties {
private boolean enabled = false;
private String[] urlPatterns = {"/*"};
private int order = 0;
}
}
@Component
public class MonitoringInterceptor implements HandlerInterceptor {
private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer requestTimer;
public MonitoringInterceptor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("http.requests")
.description("HTTP请求计数")
.register(meterRegistry);
this.requestTimer = Timer.builder("http.request.duration")
.description("HTTP请求执行时间")
.register(meterRegistry);
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
Timer.Sample sample = Timer.start(meterRegistry);
request.setAttribute("timer.sample", sample);
requestCounter.increment(
Tags.of(
"method", request.getMethod(),
"uri", request.getRequestURI()
)
);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
Timer.Sample sample = (Timer.Sample) request.getAttribute("timer.sample");
if (sample != null) {
sample.stop(requestTimer.tag("status", String.valueOf(response.getStatus())));
}
}
}
过滤器和拦截器都是Java Web开发中的重要组件,理解它们的区别和适用场景对于构建高质量的Web应用至关重要:
通过合理使用过滤器和拦截器,可以有效提高代码的可维护性、可扩展性和系统的安全性。
本文详细介绍了Java过滤器与拦截器的核心概念、实现方式、使用场景和最佳实践,希望对您的开发工作有所帮助! ✨