🌱 Spring Boot Q48 / 69

What is the role of Filter and Interceptor in Spring Boot?

AI-Powered Answer ✓ Answered

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.

java
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
    }
}
java
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.

java
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() : ""));
    }
}
java
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.

FeatureServlet FilterSpring HandlerInterceptor
Layer of OperationServlet container level, before DispatcherServletSpring MVC layer, inside DispatcherServlet
ScopeBroader, general-purpose for all requestsNarrows down to specific Spring handlers/controllers
Access to Spring ContextNo direct access to Spring application context or controller detailsFull access to Spring application context, handler, and ModelAndView
APIjakarta.servlet.Filterorg.springframework.web.servlet.HandlerInterceptor
Methodsinit(), doFilter(), destroy()preHandle(), postHandle(), afterCompletion()
Use CasesCharacter encoding, GZIP compression, general logging, basic authentication/authorization (before Spring Security), request/response modificationLogging controller execution, fine-grained access control, session management, adding common model attributes, performance monitoring of specific handlers
Bypass DispatcherServletCan short-circuit the request before it reaches Spring MVCCannot prevent request from reaching DispatcherServlet, but can prevent handler execution
DependencyStandard Servlet APISpring 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.