Kotlin, Spring Boot : HandlerInterceptor vs Filter


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
andFilter
When to Use Each
Code Examples (Including JNDI Injection Prevention at the Filter Layer)
Best Practices
HandlerInterceptor vs Filter: Core Differences
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) |
When to Use Which?
Use
HandlerInterceptor
When 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
Filter
When 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)
Code Examples
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)
Preventing JNDI Injection (Security Filter)
@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).
Best Practices
Use
Filters
For:
Security (e.g., JNDI, XSS, SQLi filters)
Infrastructure (e.g., logging, compression, CORS)
Request Wrapping (e.g., caching, modifying headers)
Use
HandlerInterceptors
For:
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.
Conclusion
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 |
Final Recommendation
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…
Subscribe to my newsletter
Read articles from Romman Sabbir directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Romman Sabbir
Romman Sabbir
Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.