'Remove ThreadLocal object within a Spring MVC website?

I have the following classes:

public class AppContext {
        
    private static final ThreadLocal<AppContextData> contextHolder = new ThreadLocal<AppContextData>() {
        
        @Override
        protected AppContextData initialValue() {
            return new AppContextData();
        }
    };
    
    public static AppContextData get() {
        return contextHolder.get();
    }
    
    public static void unset() {
        contextHolder.remove();
    }
}

public class AppContextData {
   //many getter and setter methods
}

The website starts using the ThreadLocal object in an interceptor and the object is used through out a web request.

public class MyIntercepter extends HandlerInterceptorAdapter {
            
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  {
    
        AppContext.get();
        //..... 
    }
}

I run this website on Tomcat 8.x and I find out that the log has the following error message.

20-May-2016 22:43:53.657 SEVERE [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks The web application [ROOT] created a ThreadLocal with key of type [my.organization.data.AppContext$1] (value [my.organization.data.AppContext$1@31d4463a]) and a value of type [my.organization.data.AppContextData] (value [my.organization.data.AppContextData@e89d5f4]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

How can I fix this issue?



Solution 1:[1]

JanPi already said in the comments what we have to do. In case someone wonders about the how, here it is:

public class MyIntercepter extends HandlerInterceptorAdapter {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  {
        AppContext.get();
        //..... 
    }

    public void afterCompletion(
        HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        AppContext.unset();
    }

    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        // only relevant when a handler starts an asynchronous request.
        AppContext.unset();
    }
}

The postHandle method looks like a good place, but afterCompletion is better because it's called even when the handler fails to process the request correctly (aka an exception occurred).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dube