Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the pit caused by using custom ThreadLocal storage in Spring and what is the solution?

2025-04-07 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article shows you the pits and solutions caused by the use of custom ThreadLocal storage in Spring. The content is concise and easy to understand, which will definitely brighten your eyes. I hope you can get something through the detailed introduction of this article.

Pit caused by Spring custom ThreadLocal storage

In Spring, sometimes we need to store some variables associated with Request, such as user login information, and its life cycle is the same as Request.

An easy way to implement is to use ThreadLocalpublic class SecurityContextHolder {private static final ThreadLocal securityContext = new ThreadLocal (); public static void set (SecurityContext context) {securityContext.set (context);} public static SecurityContext get () {return securityContext.get ();} public static void clear () {securityContext.remove ();}}

Use a custom HandlerInterceptor to inject relevant information

@ Slf4j@Componentpublic class RequestInterceptor implements HandlerInterceptor {@ Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {try {SecurityContextHolder.set (retrieveRequestContext (request));} catch (Exception ex) {log.warn ("failed to read request information", ex);} return true @ Override public void postHandle (HttpServletRequest request, HttpServletResponse response, Object handler, @ Nullable ModelAndView modelAndView) throws Exception {SecurityContextHolder.clear ();}

In this way, we can use the context directly in Controller, and it is very convenient to get information about users.

@ Slf4j@RestControllerclass Controller {public Result get () {long userId = SecurityContextHolder.get () .getUserId (); / /...}}

This method is also used in many blogs. However, there is a hidden hole in this method: HandlerInterceptor's postHandle is not always called.

When Exception appears in Controller

Slf4j@RestControllerclass Controller {public Result get () {long userId = SecurityContextHolder.get () .getUserId (); / /. Throw new RuntimeException ();}}

Or Exception appears in the preHandle of HandlerInterceptor

@ Slf4j@Componentpublic class RequestInterceptor implements HandlerInterceptor {@ Override public boolean preHandle (HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {try {SecurityContextHolder.set (retrieveRequestContext (request));} catch (Exception ex) {log.warn ("failed to read request information", ex);} / /. Throw new RuntimeException () / /... Return true;}}

In these cases, postHandle is not called. This causes the ThreadLocal variable not to be cleaned up.

In a normal Java environment, the ThreadLocal variable can be destroyed with the destruction of the Thread itself. However, due to the thread pool design of Spring, the thread responding to the request may be resident all the time, which results in that the variable cannot be reclaimed by GC all the time. To make matters worse, this variable that has not been properly recycled may be strung into another Request due to the reuse of threads by the thread pool, which directly leads to code logic errors.

To solve this problem, we can use the RequestContextHolder that comes with Spring, which is also based on ThreadLocal, but it is always cleaned up by the lower-level Servlet Filter, so there is no leakage problem.

Here is an example of rewriting using RequestContextHolder

Public class SecurityContextHolder {private static final String SECURITY_CONTEXT_ATTRIBUTES = "SECURITY_CONTEXT"; public static void setContext (SecurityContext context) {RequestContextHolder.currentRequestAttributes () .setAttribute (SECURITY_CONTEXT_ATTRIBUTES, context, RequestAttributes.SCOPE_REQUEST) } public static SecurityContext get () {return (SecurityContext) RequestContextHolder.currentRequestAttributes () .getAttribute (SECURITY_CONTEXT_ATTRIBUTES, RequestAttributes.SCOPE_REQUEST);}}

In addition to using RequestContextHolder, you can also use Request Scope's Bean, or ThreadLocalTargetSource, which is similar in principle.

It is important to keep in mind that ThreadLocal is the equivalent of a static variable within a thread and is a very easy point to leak, so you should be extra careful when using ThreadLocal.

The problem and principle that Threadlocal may cause memory leak

Just encountered a memory leak problem about threadlocal, just to sum up.

Let's not mention the more commonly used ones here, but directly mention the more important parts.

Why is there a memory leak? Public void set (T value) {Thread t = Thread.currentThread (); ThreadLocalMap map = getMap (t); if (map! = null) map.set (this, value); else createMap (t, value);}

In the set method, first call to the current thread thread, and each thread will have a threadlocals member variable pointing to the corresponding ThreadLocalMap, and then use the reference from the new as the key and save it with the given value.

When the external reference is released, the corresponding ThreadLocal object will not GC because it is referenced by the internal ThreadLocalMap, which may cause a memory leak.

JVM solution static class Entry extends WeakReference

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 205

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report