What's the difference between a servlet Filter and a Spring HandlerInterceptor?
Quick Answer
A servlet Filter operates at the raw Servlet API level, before the request even reaches Spring MVC's DispatcherServlet — it has no knowledge of which controller/handler method will eventually process the request, only the raw HttpServletRequest/Response. A HandlerInterceptor operates inside Spring MVC's own dispatch process, after the handler has been resolved, giving it access to the actual handler method/controller and integration with Spring's own bean lifecycle and dependency injection.
Detailed Answer
Both let you run logic around a request's processing, but they operate at different layers of the stack:
Servlet Filter (part of the raw Servlet API, jakarta.servlet.Filter) sits in front of the entire servlet container's dispatch mechanism — including, but not limited to, Spring's DispatcherServlet. A filter runs before Spring MVC even gets involved, and has no visibility into which controller/handler method will eventually process the request:
@Component
class RequestLoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
System.out.println("Incoming: " + ((HttpServletRequest) req).getRequestURI());
chain.doFilter(req, res); // must explicitly continue the chain
}
}
HandlerInterceptor (org.springframework.web.servlet.HandlerInterceptor) operates inside Spring MVC's own dispatch process, specifically around the invocation of a resolved handler — it has access to the actual HandlerMethod object (the controller and method that will run), and integrates naturally with Spring's DI:
@Component
class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
if (handler instanceof HandlerMethod hm && hm.hasMethodAnnotation(RequiresAuth.class)) {
// check auth specifically for annotated handler methods
}
return true; // false would short-circuit the request here
}
}
Registered via a WebMvcConfigurer:
@Configuration
class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/api/**");
}
}
Practical distinctions:
- Scope of applicability: a
Filterapplies to any request reaching the servlet container (static resources, other servlets, etc.), while aHandlerInterceptoronly applies to requests actually dispatched to Spring MVC handlers. - Framework awareness: a
HandlerInterceptorknows which controller method will run (useful for annotation-driven logic, like checking a custom@RequiresAuthannotation on the target method); aFilteronly sees the raw request/response. - Dependency injection: a
HandlerInterceptor, being a Spring-managed bean, naturally injects other Spring beans; aFiltercan too if registered as a Spring bean, but it's conceptually a servlet-container-level construct, existing independently of Spring MVC.
When to use which: use a Filter for concerns that should apply broadly at the servlet level regardless of Spring MVC specifics (e.g., request/response encoding, broad security header injection, basic request logging); use a HandlerInterceptor when the logic specifically needs to know about — or run just before/after — a Spring MVC handler method.