Spring MVC provides two primary mechanisms for intercepting and processing all incoming requests: servlet filters and handler interceptors. Each serves distinct purposes and operates at different layers of the application.
1. Using a Servlet Filter
A servlet filter operates before request reaches the DispatcherServlet, allowing you to inspect or modify requests and responses at the lowest level. Here is an example that validates a custom header (clientId) on every request:
@WebFilter(urlPatterns = {"/*"})
public class AuthenticationFilter implements Filter {
private static final Logger LOG = Logger.getLogger(AuthenticationFilter.class);
@Override
public void init(FilterConfig filterConfig) {
// Initialization logic if needed
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String clientId = httpRequest.getHeader("clientId");
if (StringUtils.isNotEmpty(clientId)) {
LOG.info("Client ID present, proceeding with request");
chain.doFilter(request, response);
} else {
LOG.error("Missing client ID header");
// Optionally send an error response
}
}
@Override
public void destroy() {
// Cleanup logic if needed
}
}
2. Using a Handler Interceptor
Handler interceptors operate after the DispatcherServlet has selected the handler but before the handler executes. They are more tightly integrated with the Spring MVC lifecycle. Below is an interceptor that checks for an active user session:
Step 1: Implement HandlerInterceptor
@Component
public class SecurityInterceptor implements HandlerInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(SecurityInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
request.getSession(true);
if (isLoggedIn(request)) {
return true;
}
response.getWriter().write("{\"loggedIn\":false}");
return false;
}
private boolean isLoggedIn(HttpServletRequest request) {
try {
UserSession userSession = (UserSession) request.getSession(true).getAttribute("userSession");
return userSession != null && userSession.isLoggedIn();
} catch (IllegalStateException ex) {
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// Post-processing logic if needed
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Cleanup logic if needed
}
}
Step 2: Register the Interceptor
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final HandlerInterceptor securityInterceptor;
@Autowired
public WebConfig(HandlerInterceptor securityInterceptor) {
this.securityInterceptor = securityInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(securityInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/logout");
}
}
Key Differences
- Scope: Filters work with any servlet (not limited to Spring MVC), while interceptors are part of Spring MVC’s handler execution chain.
- Lifecycle: Filters have their own lifecycle via
Filterinterface; interceptors rely onHandlerInterceptorand are managed by Spring. - Context: Interceptors have access to the handler object and
ModelAndView, making them richer for Spring-specific tasks. Filters operate withServletRequest/ServletResponse. - Path Configuration: Filters use
@WebFilter(urlPatterns)or web.xml; interceptors useInterceptorRegistrywith path matchers.
Choose filters for low-level request/response manipulation (e.g., authentication, logging, encoding). Choose interceptors for Spring MVC-specific concerns like session checks, metrics, or modifying the model before view rendering.