ThreadLocal使用步骤:
1、创建上下文本地线程
2、在容器中定义设置、获取、清理属性的方法
3、在过滤器Filter中设置本地线程熟悉(一般设置在每个服务中)
4、在服务的方法中通过容器获取属性值
4、清理本地线程属性
1、创建上下文本地线程
/**
* @author Deyou Kong
* @description 上下文容器
* @date 2023/2/28 9:59 上午
*/
public class ContextThreadLocal {
/**
* 传输token中的用户ID
*/
public static String KEY_LOGIN_USER_IN_HTTP_HEADER = "userId";
/**
* 传输token中的应用标识
*/
public static String KEY_COMPANY_SYSTEM = "system";
private static final ThreadLocal<Integer> USER_THREAD_LOCAL = new ThreadLocal<>();
private static final ThreadLocal<String> COMPANY_THREAD_LOCAL = new ThreadLocal<>();
public static Integer getUser(){
return USER_THREAD_LOCAL.get();
}
public static void setUser(Integer userId){
USER_THREAD_LOCAL.set(userId);
}
public static void removeUser(){
USER_THREAD_LOCAL.remove();
}
public static String getCompanySystem(){
return COMPANY_THREAD_LOCAL.get();
}
public static void setCompanySystem(String system){
COMPANY_THREAD_LOCAL.set(system);
}
public static void removeCompanySystem(){
COMPANY_THREAD_LOCAL.remove();
}
}
2、Web容器
package com.deyou.common.context;
import org.apache.commons.lang3.StringUtils;
/**
* 基于 ThreadLocal 封装工具类,用户保存和获取当前登录用户的ID
*/
public class WebContext {
public static void setCurrentId(Integer id){
ContextThreadLocal.setUser(id);
}
public static Integer getCurrentId(){
return ContextThreadLocal.getUser();
}
public static void removeCurrentId(){
ContextThreadLocal.removeUser();
}
public static void setCompanySystem(String system){
ContextThreadLocal.setCompanySystem(system);
}
public static String getCompanySystem(){
return StringUtils.defaultString(ContextThreadLocal.getCompanySystem(), "system");
}
public static void removeCompanySystem(){
ContextThreadLocal.removeCompanySystem();
}
}
3、在过滤器中设置本地线程的属性
package com.deyou.common.filter;
import com.deyou.common.context.ContextThreadLocal;
import com.deyou.common.context.WebContext;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author Deyou Kong
* @description 用户信息获取Filter
* @date 2023/2/28 10:27 上午
*/
public class TraceFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
this.initUserInfo((HttpServletRequest) request);
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
private void initUserInfo(HttpServletRequest request){
String userId = request.getHeader(ContextThreadLocal.KEY_LOGIN_USER_IN_HTTP_HEADER);
String system = request.getHeader(ContextThreadLocal.KEY_COMPANY_SYSTEM_IN_HTTP_HEADER);
if (StringUtils.isNotBlank(userId)){
WebContext.setCurrentId(Integer.getInteger(userId));
}
if (StringUtils.isNotBlank(system)){
WebContext.setCompanySystem(system);
}
}
}
4、清理本地线程的数据(AOP中清理)
package om.health.api.member.aop;
import com.deyou.common.context.WebContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @author Deyou Kong
* @description 控制器拦截器
* @date 2023/2/28 10:38 上午
*/
@Aspect
@Component
@Order(1)
@Slf4j
public class ControllerAop {
@Pointcut("execution(* om..*(..))" +
"&& @target(org.springframework.web.bind.annotation.RestController)" +
"&& (@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
"|| @annotation(org.springframework.web.bind.annotation.PostMapping)" +
"|| @annotation(org.springframework.web.bind.annotation.GetMapping)" +
"|| @annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
"|| @annotation(org.springframework.web.bind.annotation.PutMapping))"
)
private void controllerMethodPointcut(){}
@Around("controllerMethodPointcut()")
public void aroundFun(ProceedingJoinPoint point){
System.out.println("first");
try {
point.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("end");
}
@AfterReturning("controllerMethodPointcut()")
public void after(){
System.out.println("会话释放....");
WebContext.removeCurrentId();
WebContext.removeCompanySystem();
}
}