对于ThreadLocal的使用场景,网上的我感觉都比较不那么贴切。我就写一个目前自己项目里真实用到的场景。
我的需求场景是:用户在查询/写入数据的时候,我要拿到他的工号以及展示语言而去做对应的操作。我设想的是有那么一处地方可以拿到信息暂时存下来,后续的任何操作get一下即可,废话不多说,先上代码。
1.拦截器
/**
* @Author: zzzz
* @Date: 2024/01/28/15:46
* @Description: header信息拦截器
*/
public class HeaderInterceptor implements HandlerInterceptor {
public static final String USER_NO_HEADER = "iv_user";
public static final String LANGUAGE_CODE = "langCode";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) {
HeaderInfo headerInfo = new HeaderInfo();
//获取请求头信息
String operatorId = request.getHeader(USER_NO_HEADER);
String language = request.getHeader(LANGUAGE_CODE);
if (StringUtils.isNotBlank(operatorId)) {
headerInfo.setOperatorId(operatorId);
}
if (StringUtils.isNotBlank(language)) {
headerInfo.setLanguage(language);
}
//封装数据
HeaderContext.getHeaderContext().setHeaderInfo(headerInfo);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
HeaderContext.getHeaderContext().remove();
}
2.ThreadLocal
/**
* @Author: zzzz
* @Date: 2024/01/28/16:02
* @Description: header头信息上下文
*/
public class HeaderContext {
private static ThreadLocal<HeaderInfo> header = new ThreadLocal<>();
public HeaderContext() {
}
public static HeaderContext getHeaderContext() {
HeaderContext context = new HeaderContext();
return context;
}
public void setHeaderInfo(HeaderInfo headerInfo) {
header.set(headerInfo);
}
public String getOperationId() {
return header.get() == null ? "" : header.get().getOperatorId();
}
public String getLanguage() {
return header.get() == null ? "" : header.get().getLanguage();
}
public void remove() {
header.remove();
}
3.实体
/**
* @Author: zzzz
* @Date: 2024/01/28/15:51
* @Description: 请求头信息
*/
@Data
public class HeaderInfo {
/**
* 用户
*/
private String operatorId;
/**
* 语言
*/
private String language;
}
4.bean注入
@Bean
public HandlerInterceptor setBean() {
return new HeaderInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(setBean());
}
5.调用
String operationId = HeaderContext.getHeaderContext().getOperationId();
总结一下:
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
基于这个特性我把它用到了这里,最后提醒一下:
基于源码可以看出它是基于自身为key,传入的值作为value的键值对形式,因为key的弱引用在gc之后会变成(null,value)的形式,之后便无法回收,就会导致内存上的风险。
在使用完之后,必须要注意调用一下remove;
有错误的地方欢迎大家指出!!!来自一位菜鸟开发。