Blocking, Anti-Patterns & Thread-Safety
Master early request blocking, direct JSON error responses, filter thread-safety rules, production anti-patterns, and architectural decision trees.
Blocking, Anti-Patterns & Thread-Safety
Filters provide a powerful mechanism to inspect incoming requests early and block unauthorized calls before Spring MVC instantiates controllers.
1. Early Request Blocking & Direct JSON Error Responses
When a Filter rejects a request (e.g. missing API key), it must set the HTTP status, write a structured JSON error body, and return without calling chain.doFilter():
@Component
public class ApiKeyAuthFilter implements Filter {
private static final String API_KEY_HEADER = "X-API-KEY";
private static final String EXPECTED_KEY = "secret-api-key-123";
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String apiKey = httpRequest.getHeader(API_KEY_HEADER);
// Validation Check
if (apiKey == null || !apiKey.equals(EXPECTED_KEY)) {
// 1. Set HTTP 401 Unauthorized
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.setContentType("application/json");
httpResponse.setCharacterEncoding("UTF-8");
// 2. Write direct JSON error response
httpResponse.getWriter().write("""
{
"status": 401,
"error": "Unauthorized",
"message": "Invalid or missing X-API-KEY header"
}
""");
// 3. RETURN IMMEDIATELY (Do NOT call chain.doFilter!)
return;
}
// Request valid -> continue downstream
chain.doFilter(request, response);
}
}2. Thread-Safety & Stateless Filter Rules
In Spring Boot, Filters declared as @Component are Singleton Beans shared across all concurrent HTTP threads:
Thread-Safety Hazard: NEVER store request-specific data in Filter instance fields! Mutable instance fields create severe multi-threaded race conditions where User A's data can leak to User B!
Bad (Thread-Unsafe Anti-Pattern)
@Component
public class UnsafeFilter implements Filter {
// DANGEROUS! Instance field shared across all concurrent requests!
private String requestUser;
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
requestUser = req.getParameter("user"); // Thread Race Condition!
chain.doFilter(req, res);
}
}Good (Thread-Safe Production Pattern)
@Component
public class SafeFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
// Thread-safe: Local method variable isolated to current execution stack
String requestUser = req.getParameter("user");
chain.doFilter(req, res);
}
}3. Production Anti-Patterns Matrix
| Anti-Pattern | Risk / Problem | Correct Engineering Solution |
|---|---|---|
| 1. Business Logic in Filter | Couples domain rules to Servlet infrastructure | Keep business logic inside @Service classes |
| 2. Database Query Per Request | Creates global system latency bottlenecks ($10,000$ DB calls/sec) | Perform DB lookups in services or cache tokens in memory |
3. Forgetting chain.doFilter() | Requests hang or return blank responses unexpectedly | Call chain.doFilter() unless intentionally blocking |
| 4. Logging Auth Passwords/Tokens | Credentials leak into production log files | Mask or omit sensitive headers from logger outputs |
| 5. Header Mutation After Response Committed | Triggers IllegalStateException or silent header loss | Set mandatory response headers before chain.doFilter() |
4. Architectural Decision Tree
DO I NEED A FILTER?
│
├── Is the logic an HTTP/Servlet infrastructure concern? (Logging, headers, timing) ──► USE FILTER
├── Does the logic need to run BEFORE DispatcherServlet? ─────────────────────────────► USE FILTER
├── Does the logic depend on the target Controller handler method? ───────────────────► USE INTERCEPTOR
├── Is it full enterprise authentication & authorization? ───────────────────────────► USE SPRING SECURITY
└── Is it core business domain logic? ────────────────────────────────────────────────► USE SERVICE LAYER❓ Interactive Self-Assessment
Why are instance fields inside a Spring-managed Filter bean unsafe for storing request parameters?
Designing an Early Request Rejection Filter
Requirements:
- Intercept all requests and inspect the
X-Client-IDheader. - If
X-Client-IDis missing or empty, return HTTP400 Bad Requestwith a JSON payload{"error": "Missing X-Client-ID header"}. - Ensure no downstream filters or controllers execute when
X-Client-IDis missing. - Ensure the filter is completely thread-safe.
Production Logging, Timing & Trace IDs
Master production-grade filter patterns, request timing with try-finally, correlation IDs, response header injection, and sensitive data logging security.
Response Mutation & ContentCachingResponseWrapper
Master Servlet response mutation, header timing, response commitment rules, ContentCachingResponseWrapper, and copyBodyToResponse mechanics.