Filters are a fundamental part of the Servlet API. They operate at the servlet level, meaning they intercept requests before they reach your Spring MVC dispatcher servlet (and thus, your Spring controllers) and responses after they leave it.
Key Characteristics of Filters:
- Servlet API Component: Filters are defined by the Java Servlet specification (
javax.servlet.Filter
). This means they are not specific to Spring and can be used in any Servlet-based application. - Request/Response Level: They primarily deal with the raw
HttpServletRequest
andHttpServletResponse
objects. - Chain of Responsibility: Multiple filters can be chained together. Each filter in the chain has the opportunity to process the request and response, and can either pass the control to the next filter in the chain or terminate the processing.
- Aware of Servlet Context: Filters have access to the
ServletContext
. - Lifecycle: Filters have a lifecycle managed by the Servlet container (e.g., Tomcat, Jetty). This includes initialization (
init
), processing (doFilter
), and destruction (destroy
) phases.
When to Use Filters:
Filters are excellent for tasks that need to be performed on all or a specific set of requests and responses before Spring MVC even gets involved. Common use cases include:
- Logging: Logging incoming request details (IP address, URL, headers) and outgoing response status.
- Authentication and Authorization: Checking if a user is authenticated and has the necessary roles before the request reaches the controller.
- Request/Response Modification: Adding or modifying headers, compressing responses, encoding requests.
- Character Encoding: Setting the character encoding for requests and responses.
- Security Headers: Adding security-related headers like
Content-Security-Policy
orX-Frame-Options
. - Performance Monitoring: Measuring the time taken for the entire request-response cycle at the servlet level.
- CORS (Cross-Origin Resource Sharing): Handling cross-origin requests.
Implementing a Filter in Spring Boot:
- Create a Class Implementing
javax.servlet.Filter
:
import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import java.io.IOException; @Component public class RequestLoggingFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(RequestLoggingFilter.class); @Override public void init(jakarta.servlet.FilterConfig filterConfig) throws ServletException { logger.info("RequestLoggingFilter initialized"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; logger.info("Request received: {} {}", httpRequest.getMethod(), httpRequest.getRequestURI()); long startTime = System.currentTimeMillis(); try { chain.doFilter(request, response); // Pass the request and response down the filter chain } finally { long endTime = System.currentTimeMillis(); logger.info("Response sent: {} - {} in {}ms", httpResponse.getStatus(), httpRequest.getRequestURI(), (endTime - startTime)); } } @Override public void destroy() { logger.info("RequestLoggingFilter destroyed"); } }
2. Overview of Interceptors in Spring Boot
Interceptors in Spring Boot are part of the Spring Web MVC framework and provide an additional layer of processing after the request is passed through the filters but before the request reaches the controller. They are specifically designed to work with Spring’s MVC lifecycle and offer more advanced functionality like handling method invocation in controllers.
Key Characteristics of Interceptors:
- Spring-Specific: Interceptors are part of Spring’s
HandlerInterceptor
interface, which is specific to Spring applications and works in the context of Spring’s MVC lifecycle. - Operate at a higher level: Interceptors can intercept the execution of a handler (controller) method. They can modify the
ModelAndView
or even stop the execution of the handler method. - Access to Spring’s DispatcherServlet: Interceptors have access to the Spring MVC
HandlerMapping
,ModelAndView
, and other Spring components, which allows for more control over the request processing. - Do not modify HTTP requests directly: Unlike filters, interceptors cannot modify HTTP request/response objects directly. Instead, they can modify the
ModelAndView
or return custom results before or after controller execution.
Use Cases for Interceptors:
- Logging request handling times.
- Modifying or enriching the model before it is sent to the view (e.g., adding common attributes).
- Implementing pre/post-controller logic (e.g., user authentication/authorization).
- Performance monitoring.
- Validating user sessions.
Example: Using an Interceptor in Spring Boot
To create an interceptor, implement the HandlerInterceptor
interface:
import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyRequestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("Pre Handle method is Calling"); return true; // Return true to allow the request to proceed to the controller } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("Post Handle method is Calling"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("Request and Response is completed"); } }
To register the interceptor, you need to configure it within WebMvcConfigurer
:
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyRequestInterceptor()) .addPathPatterns("/api/*"); // Apply interceptor to specific URL pattern } }
3. Key Differences Between Filters and Interceptors
Feature | Filters | Interceptors |
---|---|---|
Part of | Servlet API (Java EE) | Spring MVC Framework |
Execution Order | Executes before the request reaches the servlet or controller | Executes after filters, before/after controller methods |
Scope | Global (applies to all requests) or specific URL patterns | Specific to Spring MVC controllers and handler methods |
Access to HTTP Objects | Has access to request and response objects | Does not modify HTTP request/response directly, works with ModelAndView |
Purpose | General-purpose processing (e.g., logging, security checks) | Controller-specific logic (e.g., pre/post handling) |
Access to Spring Context | No access to Spring’s DispatcherServlet | Has access to Spring’s HandlerMapping , ModelAndView |
Lifecycle | Configured as part of the servlet container lifecycle | Configured as part of Spring’s MVC lifecycle |
Modification of Request/Response | Can modify the request and response directly | Cannot modify the request or response directly, can modify ModelAndView |
4. Use Case Example: Logging with Filter and Interceptor
Let’s imagine you want to log every incoming request and response status. You can use both filters and interceptors to achieve this:
Filter Example (Logging Filter):
@WebFilter("/*") public class LoggingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("Request URI: " + ((HttpServletRequest) request).getRequestURI()); chain.doFilter(request, response); System.out.println("Response Status: " + ((HttpServletResponse) response).getStatus()); } }
Interceptor Example (Logging Interceptor):
public class LoggingInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("Pre Handle - Request URI: " + request.getRequestURI()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) { System.out.println("Post Handle - Response Status: " + response.getStatus()); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { System.out.println("After Completion"); } }
In both cases, you are logging the request and response, but the filter operates at the servlet level (before it reaches the Spring controller), while the interceptor operates at the Spring MVC controller level.
Conclusion
- Filters are best for tasks that involve general request/response manipulation (e.g., security, logging) and are part of the Servlet API.
- Interceptors are best for Spring MVC-specific tasks, like pre/post-processing before and after controller methods, and offer more flexibility with Spring-specific features.
Choosing between filters and interceptors depends on your specific use case and the level at which you want to interact with the request and response objects. If you need to work within the Spring MVC lifecycle and need access to the ModelAndView
, interceptors are the better choice. For more general-purpose processing, filters will be more suitable.