ThreadLocal是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据。在应用中,通常用来保存一些需要多次调用的数据,减少用户请求和代码量,而且数据对于其他线程是隔离的。
简介
从名字我们就可以看到ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
从实际使用的角度来看,可以有以下用途:
- 在进行对象跨层传递的时候,使用ThreadLocal可以避免多次传递,打破层次间的约束。
- 线程间数据隔离。
- 进行事务操作,用于存储线程事务信息。
- 数据库连接,Session会话管理。
实际应用
以保存用户信息为例,ThreadLocal可以把用户信息保存在线程中,用户发来的每一次请求启动的线程到保存了用户信息,当请求结束,我们会把保存的用户信息清除掉,这样就方便我们在开发中获取用户登录信息。
实现方式
- 创建一个ThreadLocal类,创建一个ThreadLocal对象,设置ThreadLocal的set,remove,get方法;
- 定义一个登录的拦截器类,实现HandlerInterceptor ,重写 preHandle() 和afterCompletion()方法 ,preHandle ()方法把登录信息写入ThreadLocal,afterCompletion()方法清除登录信息;
- 设置一些配置信息,创建一个类实现 WebMvcConfigurer ,重写addInterceptors()方法,创建一个登录拦截器类的对象,给他添加到配置中。
ThreadLocal类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class ThreadLocalUser { private ThreadLocalUser(){ } private static final ThreadLocal<UserInfo> userLocal = new ThreadLocal<>();
public static void remove() { userLocal.remove(); }
public static void set(UserInfo userInfo) { userLocal.set(userInfo); }
public static UserInfo get() { return userLocal.get(); } }
|
登录拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { UserInfo userInfo = getUserInfo(request); ThreadLocalUser.set(userInfo); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) { ThreadLocalUser.remove(); } }
|
WebConfig
1 2 3 4 5 6 7 8 9 10
| @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/**"); } }
|