Filter vs Interceptor in Spring Boot: Real-World Examples and Best Practices

 

In a modern Spring Boot backend, it’s common to intercept HTTP requests for cross-cutting concerns like authentication, authorization, logging, or header injection.

Spring provides two powerful mechanisms to achieve this:

  • Servlet Filters

  • Spring MVC Interceptors

They may seem similar, but they’re designed for different stages of the request lifecycle. In this blog, we’ll explore the differences, real-world examples, and when to use which — backed by best practices.


Quick Comparison: Filter vs Interceptor

FeatureFilterInterceptor
API LevelServlet (jakarta.servlet.Filter)Spring MVC (HandlerInterceptor)
Execution PointBefore DispatcherServletBefore/after controller methods
Intercepts static resources?✅ Yes❌ No
Access to controller method?❌ No✅ Yes (via handler)
Can block requests?✅ Yes (by skipping chain.doFilter())✅ Yes (by returning false in preHandle)
Use CasesCORS, headers, logging, early auth checksRole-based auth, audit logging, business pre-checks

Request Lifecycle in Spring Boot

text
Client └─> Filter └─> DispatcherServlet └─> Interceptor (preHandle) └─> Controller └─> Interceptor (postHandle) └─> Interceptor (afterCompletion)

When Should You Use a Filter?

Filters are ideal for low-level request manipulation and global request concerns, such as:

  • Logging all traffic (including static resources)

  • Enabling CORS headers

  • Authentication token parsing

  • Charset/encoding setup

Example: Global CORS Filter

java
@Component public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Auth-Token"); chain.doFilter(req, res); } }

When Should You Use an Interceptor?

Interceptors are perfect for Spring MVC–specific use cases, such as:

  • Role-based access control (RBAC)

  • Request preprocessing based on controller annotations

  • Audit logging

  • Adding attributes to the model

✅ Example: Interceptor for Admin Authorization

java
@Component public class AdminInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { String role = request.getHeader("X-User-Role"); if (!"ADMIN".equalsIgnoreCase(role)) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("Access Denied: Admins only"); return false; } return true; } }

🛠 Register in WebMvcConfigurer

java
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private AdminInterceptor adminInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(adminInterceptor).addPathPatterns("/admin/**"); } }

Real-World Use Case: Combining Filter and Interceptor

Let’s say you’re building a secure API:

  • You validate JWT tokens in every request → ✅ Filter

  • You check user roles after token validation → ✅ Interceptor

Step 1: JWT Filter

java
@Component public class JwtTokenFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("Missing or invalid Authorization header"); return; } // Parse token, extract role (mocked here) String userRole = "ADMIN"; request.setAttribute("userRole", userRole); filterChain.doFilter(request, response); } }

Step 2: Role-Based Interceptor

java
@Component public class RoleInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { String role = (String) request.getAttribute("userRole"); if (!"ADMIN".equals(role)) { response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.getWriter().write("Access denied: ADMINs only"); return false; } return true; } }

Summary: Filter vs Interceptor

Use CaseFilterInterceptor
Logging static and dynamic requests✅ Yes❌ No
Authentication (e.g., token parsing)✅ Yes❌ Not ideal
Authorization (based on role/annotation)❌ No✅ Yes
Modify request before controller✅ Yes✅ Yes
Access handler method/controller details❌ No✅ Yes
Execution orderFirstAfter filter

Final Thoughts

In most Spring Boot applications, you’ll find yourself using both Filters and Interceptors — not as alternatives but as complements:

  • Use Filters for infrastructure-level concerns (tokens, CORS, headers)

  • Use Interceptors for application-specific logic (RBAC, audit, pre/post handling)

Understanding where each fits in the request lifecycle ensures cleaner architecture, easier debugging, and maintainable code.

Post a Comment

0 Comments