Kotlin, Spring Boot : HandlerInterceptor vs Filter
HandlerInterceptor vs Filter in Spring Boot: A Practical Guide with JNDI Injection Prevention

Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
Search for a command to run...
HandlerInterceptor vs Filter in Spring Boot: A Practical Guide with JNDI Injection Prevention

Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
No comments yet. Be the first to comment.
A practical guide to choosing the right coroutine primitive for your Android/Kotlin projects

This guide explains what Channels are, when to use them, how to use them correctly, and when NOT to use them — in simple, professional language. 1. What problem do Channels solve? In Kotlin coroutines, you often have multiple coroutines running at t...

Learn how to build preview-safe ViewModels in Jetpack Compose using Hilt.

Simple In-Memory Caching: A Tiny Trick with Massive Impact

In Spring Boot, both Filters and HandlerInterceptors help us intercept HTTP requests and responses, but they work at different levels in the app. Picking the right one depends on what you need—whether it's low-level request handling with a Filter or more Spring-aware processing with a HandlerInterceptor.
In this article, we'll explore:
Key Differences between HandlerInterceptor and Filter
When to Use Each
Code Examples (Including JNDI Injection Prevention at the Filter Layer)
Best Practices
| Feature | HandlerInterceptor | Filter |
| Layer | Spring MVC (after DispatcherServlet) | Servlet (before DispatcherServlet) |
| Spring Context | Full DI support | ❌ No DI (unless manually bridged) |
| Access to | Controller metadata (e.g., @RequestMapping) | Raw ServletRequest/ServletResponse |
| Execution Order | After routing, before controller logic | Before Spring processes the request |
| Modify Response | Limited (cannot modify body easily) | Full control (via ServletResponse) |
| Use Cases | - Auth checks based on annotations | - Logging |
| - Request/response logging | - Request/response modification | |
| - Adding global model attributes | - Security (CORS, JNDI protection) |
Use
HandlerInterceptorWhen You Need:
Spring Dependency Injection (e.g., @Autowired services)
Access to Controller Metadata (e.g., method annotations)
Pre/Post-Processing Around Controllers (e.g., logging execution time)
Use
FilterWhen You Need:
Low-Level Request/Response Manipulation (e.g., modifying headers)
Block Requests Before Spring Processes Them (e.g., security checks)
Servlet-Specific Features (e.g., HttpServletRequest wrappers)
Example 1: HandlerInterceptor (Spring-Aware)
@Component
class AuthInterceptor(
private val authService: AuthService // DI works
) : HandlerInterceptor {
override fun preHandle(
request: HttpServletRequest,
response: HttpServletResponse,
handler: Any
): Boolean {
if (!authService.isValidToken(request.getHeader("X-Auth-Token"))) {
response.status = HttpStatus.UNAUTHORIZED.value()
return false
}
return true
}
}
// Registration
@Configuration
class WebConfig : WebMvcConfigurer {
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(AuthInterceptor())
}
}
Example 2: Filter (Servlet-Level)
@Component
@Order(1) // High priority for security
class JndiInjectionFilter : Filter {
override fun doFilter(
request: ServletRequest,
response: ServletResponse,
chain: FilterChain
) {
val httpRequest = request as HttpServletRequest
// Block JNDI lookup attempts (e.g., Log4Shell)
if (httpRequest.queryString?.lowercase()?.contains("jndi:") == true) {
(response as HttpServletResponse).sendError(
HttpStatus.FORBIDDEN.value(),
"JNDI lookup blocked"
)
return
}
chain.doFilter(request, response)
}
}
Why This Works:
Filters run before Spring processes the request.
Blocks malicious jndi: patterns (e.g., Log4Shell exploits).
Does not rely on Spring (works at the servlet level).
Use
FiltersFor:
Security (e.g., JNDI, XSS, SQLi filters)
Infrastructure (e.g., logging, compression, CORS)
Request Wrapping (e.g., caching, modifying headers)
Use
HandlerInterceptorsFor:
Business Logic (e.g., role-based auth checks)
Controller-Specific Logic (e.g., @PreAuthorize-like checks)
Post-Processing (e.g., adding response headers after execution)
Avoid:
Using Filters for Spring-specific tasks.
Using Interceptors for raw request/response modification.
| Aspect | Filter | HandlerInterceptor |
| Best For | Security, logging, raw manipulation | Business logic, Spring integration |
| Execution Point | Before Spring | After routing, before controller |
| Spring DI Support | No | Yes |
| Use Case Example | JNDI injection blocking | Role-based auth checks |
For security (e.g., JNDI, CORS) → Use Filter.
For Spring-aware logic (e.g., auth, logging) → Use HandlerInterceptor.
That’s it for today. Happy coding…