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
@Componentpublic class TenantContextInterceptor implements HandlerInterceptor {private static final ThreadLocal<String> TENANT_HOLDER = new ThreadLocal<>();public static String getCurrentTenant() {return TENANT_HOLDER.get();}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String tenantId = request.getHeader("X-Tenant-ID");if (tenantId != null) {TENANT_HOLDER.set(tenantId);}return true;}@Overridepublic 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.