0 day streak
java / intermediate
Snippet

ThreadLocal Memory Leak Prevention in Custom Spring Interceptors

When using ThreadLocal variables in a thread-pooled environment like Spring MVC on Tomcat, failing to invoke remove() in afterCompletion causes memory leaks and stale tenant context retention across reused worker threads.

snippet.java
java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class TenantContextInterceptor implements HandlerInterceptor {
private static final ThreadLocal<String> TENANT_HOLDER = new ThreadLocal<>();
public static String getCurrentTenant() {
return TENANT_HOLDER.get();
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String tenantId = request.getHeader("X-Tenant-ID");
if (tenantId != null) {
TENANT_HOLDER.set(tenantId);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
TENANT_HOLDER.remove();
}
}
spring
Breakdown
1
private static final ThreadLocal<String> TENANT_HOLDER = new ThreadLocal<>();
Maintains thread-confined state across service boundaries for the active HTTP request.
2
TENANT_HOLDER.set(tenantId);
Allocates tenant identity in the current thread's ThreadLocalMap.
3
TENANT_HOLDER.remove();
Explicitly removes the entry in afterCompletion to prevent memory leaks during thread reuse.