What is the role of Filter and Interceptor in Spring Boot?
In Spring Boot applications, both Filters and Interceptors provide mechanisms to intercept and process web requests before they reach the controller or after the controller has processed them. While they serve similar high-level goals of cross-cutting concerns, they operate at different layers of the application stack, offering distinct capabilities and use cases.
Servlet Filter
A Servlet Filter is a component that operates at the Servlet container level, outside the Spring DispatcherServlet. It intercepts requests before they even hit the DispatcherServlet and also intercepts responses after they leave the DispatcherServlet but before being sent back to the client. Filters are part of the Java Servlet API and are generic to any web application built on Servlet technology, not just Spring.
Filters are typically used for broad, general-purpose tasks such as logging, authentication (before Spring Security takes over), request/response modification (e.g., character encoding, GZIP compression), and auditing. They operate on the raw HttpServletRequest and HttpServletResponse objects, making them suitable for tasks that don't require knowledge of Spring's MVC context (like the handler or model).
Key methods of the Filter interface are init(), doFilter(), and destroy(). The doFilter() method is where the interception logic resides. It receives the ServletRequest, ServletResponse, and FilterChain objects.
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
public class MySimpleFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// Initialization logic
}
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
System.out.println("Incoming request through Filter: " + httpRequest.getRequestURI());
// Pass the request along the filter chain
chain.doFilter(request, response);
System.out.println("Outgoing response through Filter: " + httpRequest.getRequestURI());
}
@Override
public void destroy() {
// Cleanup logic
}
}
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<MySimpleFilter> loggingFilter() {
FilterRegistrationBean<MySimpleFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new MySimpleFilter());
registrationBean.addUrlPatterns("/api/*"); // Apply to specific URL patterns
registrationBean.setOrder(1); // Set order if multiple filters are present
return registrationBean;
}
}
Spring Interceptor
A Spring Interceptor (specifically, a HandlerInterceptor) operates at the Spring MVC layer, within the DispatcherServlet's processing pipeline. It provides more fine-grained control over the request lifecycle, with access to the handler (controller method) that will be invoked, the ModelAndView object, and any exceptions thrown.
Interceptors are ideal for tasks that require awareness of the Spring MVC context, such as logging pre- and post-controller execution, applying security checks specific to certain controllers or methods, manipulating model data, or adding common attributes to the model. They can inspect and modify requests and responses, but their primary strength lies in their integration with Spring's handler mapping.
The HandlerInterceptor interface provides three methods: preHandle(), postHandle(), and afterCompletion(). * preHandle(): Called before the handler (controller method) is executed. Returns true to proceed, false to stop. * postHandle(): Called after the handler has executed but before the view is rendered. Can modify the ModelAndView. * afterCompletion(): Called after the complete request has finished and the view has been rendered (or an exception occurred). Useful for resource cleanup.
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MySimpleInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("Pre-handle interceptor logic for: " + request.getRequestURI());
// Return true to continue processing, false to stop
return true;
}
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("Post-handle interceptor logic for: " + request.getRequestURI());
if (modelAndView != null) {
modelAndView.addObject("interceptorMessage", "Processed by interceptor");
}
}
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) throws Exception {
System.out.println("After-completion interceptor logic for: " + request.getRequestURI() + (ex != null ? ", Exception: " + ex.getMessage() : ""));
}
}
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 WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MySimpleInterceptor())
.addPathPatterns("/api/**") // Apply to specific URL patterns
.excludePathPatterns("/api/public/**"); // Exclude certain patterns
}
}
Key Differences and Use Cases
Understanding the operational layer is crucial for deciding whether to use a Filter or an Interceptor. While both can perform request processing, their integration points and access to application context differ significantly.
| Feature | Servlet Filter | Spring HandlerInterceptor |
|---|---|---|
| Layer of Operation | Servlet container level, before DispatcherServlet | Spring MVC layer, inside DispatcherServlet |
| Scope | Broader, general-purpose for all requests | Narrows down to specific Spring handlers/controllers |
| Access to Spring Context | No direct access to Spring application context or controller details | Full access to Spring application context, handler, and ModelAndView |
| API | jakarta.servlet.Filter | org.springframework.web.servlet.HandlerInterceptor |
| Methods | init(), doFilter(), destroy() | preHandle(), postHandle(), afterCompletion() |
| Use Cases | Character encoding, GZIP compression, general logging, basic authentication/authorization (before Spring Security), request/response modification | Logging controller execution, fine-grained access control, session management, adding common model attributes, performance monitoring of specific handlers |
| Bypass DispatcherServlet | Can short-circuit the request before it reaches Spring MVC | Cannot prevent request from reaching DispatcherServlet, but can prevent handler execution |
| Dependency | Standard Servlet API | Spring MVC Framework |
In summary, use a Filter for concerns that are independent of Spring's MVC context and operate at a lower level, affecting all web requests globally. Use an Interceptor for concerns tightly coupled with the Spring MVC workflow, requiring knowledge of the specific handler being invoked or the ModelAndView, and offering more control over the Spring MVC lifecycle.