add 新增 ThreadLocalHolder 替代 SaHolder 支持异步

add 新增 ThreadLocalHolder 替代 SaHolder 支持异步
dev
疯狂的狮子Li 2 years ago
parent 77cfb9137e
commit c68eb5701b

@ -99,6 +99,11 @@
<artifactId>ip2region</artifactId> <artifactId>ip2region</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -0,0 +1,57 @@
package org.dromara.common.core.context;
import com.alibaba.ttl.TransmittableThreadLocal;
import java.util.HashMap;
import java.util.Map;
/**
* 线
*
* @author Michelle.Chung
*/
public class ThreadLocalHolder {
/**
* ()
*/
private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = TransmittableThreadLocal.withInitial(HashMap::new);
/**
*
*
* @param key
* @param value
*/
public static <T> void set(String key, T value) {
THREAD_LOCAL.get().put(key, value);
}
/**
*
*
* @param key
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T get(String key) {
return (T) THREAD_LOCAL.get().get(key);
}
/**
*
*
* @param key
*/
public static void remove(String key) {
THREAD_LOCAL.get().remove(key);
}
/**
*
*/
public static void clear() {
THREAD_LOCAL.remove();
}
}

@ -1,13 +1,13 @@
package org.dromara.common.dict.service.impl; package org.dromara.common.dict.service.impl;
import cn.dev33.satoken.context.SaHolder;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.common.core.constant.CacheConstants; import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.context.ThreadLocalHolder;
import org.dromara.common.core.service.DictService; import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.StreamUtils; import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.system.api.RemoteDictService; import org.dromara.system.api.RemoteDictService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.system.api.domain.vo.RemoteDictDataVo; import org.dromara.system.api.domain.vo.RemoteDictDataVo;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -35,14 +35,13 @@ public class DictServiceImpl implements DictService {
* @param separator * @param separator
* @return * @return
*/ */
@SuppressWarnings("unchecked cast")
@Override @Override
public String getDictLabel(String dictType, String dictValue, String separator) { public String getDictLabel(String dictType, String dictValue, String separator) {
// 优先从本地缓存获取 // 优先从本地缓存获取
List<RemoteDictDataVo> datas = (List<RemoteDictDataVo>) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); List<RemoteDictDataVo> datas = ThreadLocalHolder.get(CacheConstants.SYS_DICT_KEY + dictType);
if (ObjectUtil.isNull(datas)) { if (ObjectUtil.isNull(datas)) {
datas = remoteDictService.selectDictDataByType(dictType); datas = remoteDictService.selectDictDataByType(dictType);
SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); ThreadLocalHolder.set(CacheConstants.SYS_DICT_KEY + dictType, datas);
} }
Map<String, String> map = StreamUtils.toMap(datas, RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel); Map<String, String> map = StreamUtils.toMap(datas, RemoteDictDataVo::getDictValue, RemoteDictDataVo::getDictLabel);
@ -63,14 +62,13 @@ public class DictServiceImpl implements DictService {
* @param separator * @param separator
* @return * @return
*/ */
@SuppressWarnings("unchecked cast")
@Override @Override
public String getDictValue(String dictType, String dictLabel, String separator) { public String getDictValue(String dictType, String dictLabel, String separator) {
// 优先从本地缓存获取 // 优先从本地缓存获取
List<RemoteDictDataVo> datas = (List<RemoteDictDataVo>) SaHolder.getStorage().get(CacheConstants.SYS_DICT_KEY + dictType); List<RemoteDictDataVo> datas = ThreadLocalHolder.get(CacheConstants.SYS_DICT_KEY + dictType);
if (ObjectUtil.isNull(datas)) { if (ObjectUtil.isNull(datas)) {
datas = remoteDictService.selectDictDataByType(dictType); datas = remoteDictService.selectDictDataByType(dictType);
SaHolder.getStorage().set(CacheConstants.SYS_DICT_KEY + dictType, datas); ThreadLocalHolder.set(CacheConstants.SYS_DICT_KEY + dictType, datas);
} }
Map<String, String> map = StreamUtils.toMap(datas, RemoteDictDataVo::getDictLabel, RemoteDictDataVo::getDictValue); Map<String, String> map = StreamUtils.toMap(datas, RemoteDictDataVo::getDictLabel, RemoteDictDataVo::getDictValue);

@ -5,6 +5,7 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.context.ThreadLocalHolder;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MessageUtils; import org.dromara.common.core.utils.MessageUtils;
@ -36,7 +37,7 @@ import java.util.StringJoiner;
@Aspect @Aspect
public class RepeatSubmitAspect { public class RepeatSubmitAspect {
private static final ThreadLocal<String> KEY_CACHE = new ThreadLocal<>(); private static final String KEY_CACHE = "keyCache";
@Before("@annotation(repeatSubmit)") @Before("@annotation(repeatSubmit)")
public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable { public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
@ -59,7 +60,7 @@ public class RepeatSubmitAspect {
// 唯一标识指定key + url + 消息头) // 唯一标识指定key + url + 消息头)
String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey; String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey;
if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) { if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) {
KEY_CACHE.set(cacheRepeatKey); ThreadLocalHolder.set(KEY_CACHE, cacheRepeatKey);
} else { } else {
String message = repeatSubmit.message(); String message = repeatSubmit.message();
if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) { if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
@ -82,9 +83,10 @@ public class RepeatSubmitAspect {
if (r.getCode() == R.SUCCESS) { if (r.getCode() == R.SUCCESS) {
return; return;
} }
RedisUtils.deleteObject(KEY_CACHE.get()); String cacheKey = ThreadLocalHolder.get(KEY_CACHE);
RedisUtils.deleteObject(cacheKey);
} finally { } finally {
KEY_CACHE.remove(); ThreadLocalHolder.remove(KEY_CACHE);
} }
} }
} }
@ -97,8 +99,9 @@ public class RepeatSubmitAspect {
*/ */
@AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e") @AfterThrowing(value = "@annotation(repeatSubmit)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) { public void doAfterThrowing(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Exception e) {
RedisUtils.deleteObject(KEY_CACHE.get()); String cacheKey = ThreadLocalHolder.get(KEY_CACHE);
KEY_CACHE.remove(); RedisUtils.deleteObject(cacheKey);
ThreadLocalHolder.remove(KEY_CACHE);
} }
/** /**

@ -27,11 +27,6 @@
<artifactId>ruoyi-common-json</artifactId> <artifactId>ruoyi-common-json</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId> <artifactId>dubbo-spring-boot-starter</artifactId>

@ -4,7 +4,6 @@ import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -14,6 +13,7 @@ import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.dromara.common.core.context.ThreadLocalHolder;
import org.dromara.common.core.utils.ServletUtils; import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
@ -49,9 +49,9 @@ public class LogAspect {
/** /**
* * key
*/ */
private static final ThreadLocal<StopWatch> TIME_THREADLOCAL = new TransmittableThreadLocal<>(); private static final String LOG_STOP_WATCH_KEY = "logStopwatch";
/** /**
* *
@ -59,7 +59,7 @@ public class LogAspect {
@Before(value = "@annotation(controllerLog)") @Before(value = "@annotation(controllerLog)")
public void boBefore(JoinPoint joinPoint, Log controllerLog) { public void boBefore(JoinPoint joinPoint, Log controllerLog) {
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
TIME_THREADLOCAL.set(stopWatch); ThreadLocalHolder.set(LOG_STOP_WATCH_KEY, stopWatch);
stopWatch.start(); stopWatch.start();
} }
@ -112,7 +112,7 @@ public class LogAspect {
// 处理设置注解上的参数 // 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult); getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间 // 设置消耗时间
StopWatch stopWatch = TIME_THREADLOCAL.get(); StopWatch stopWatch = ThreadLocalHolder.get(LOG_STOP_WATCH_KEY);
stopWatch.stop(); stopWatch.stop();
operLog.setCostTime(stopWatch.getTime()); operLog.setCostTime(stopWatch.getTime());
// 发布事件保存数据库 // 发布事件保存数据库
@ -122,7 +122,7 @@ public class LogAspect {
log.error("异常信息:{}", exp.getMessage()); log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace(); exp.printStackTrace();
} finally { } finally {
TIME_THREADLOCAL.remove(); ThreadLocalHolder.remove(LOG_STOP_WATCH_KEY);
} }
} }
@ -161,7 +161,7 @@ public class LogAspect {
Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
String requestMethod = operLog.getRequestMethod(); String requestMethod = operLog.getRequestMethod();
if (MapUtil.isEmpty(paramsMap) if (MapUtil.isEmpty(paramsMap)
&& HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) { && HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000)); operLog.setOperParam(StringUtils.substring(params, 0, 2000));
} else { } else {

@ -1,7 +1,5 @@
package org.dromara.common.satoken.utils; package org.dromara.common.satoken.utils;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaStorage;
import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginModel; import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
@ -11,6 +9,7 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.dromara.common.core.constant.TenantConstants; import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.constant.UserConstants; import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.context.ThreadLocalHolder;
import org.dromara.common.core.enums.UserType; import org.dromara.common.core.enums.UserType;
import org.dromara.system.api.model.LoginUser; import org.dromara.system.api.model.LoginUser;
@ -47,11 +46,10 @@ public class LoginHelper {
* @param model * @param model
*/ */
public static void login(LoginUser loginUser, SaLoginModel model) { public static void login(LoginUser loginUser, SaLoginModel model) {
SaStorage storage = SaHolder.getStorage(); ThreadLocalHolder.set(LOGIN_USER_KEY, loginUser);
storage.set(LOGIN_USER_KEY, loginUser); ThreadLocalHolder.set(TENANT_KEY, loginUser.getTenantId());
storage.set(TENANT_KEY, loginUser.getTenantId()); ThreadLocalHolder.set(USER_KEY, loginUser.getUserId());
storage.set(USER_KEY, loginUser.getUserId()); ThreadLocalHolder.set(DEPT_KEY, loginUser.getDeptId());
storage.set(DEPT_KEY, loginUser.getDeptId());
model = ObjectUtil.defaultIfNull(model, new SaLoginModel()); model = ObjectUtil.defaultIfNull(model, new SaLoginModel());
StpUtil.login(loginUser.getLoginId(), StpUtil.login(loginUser.getLoginId(),
model.setExtra(TENANT_KEY, loginUser.getTenantId()) model.setExtra(TENANT_KEY, loginUser.getTenantId())
@ -161,10 +159,10 @@ public class LoginHelper {
public static Object getStorageIfAbsentSet(String key, Supplier<Object> handle) { public static Object getStorageIfAbsentSet(String key, Supplier<Object> handle) {
try { try {
Object obj = SaHolder.getStorage().get(key); Object obj = ThreadLocalHolder.get(key);
if (ObjectUtil.isNull(obj)) { if (ObjectUtil.isNull(obj)) {
obj = handle.get(); obj = handle.get();
SaHolder.getStorage().set(key, obj); ThreadLocalHolder.set(key, obj);
} }
return obj; return obj;
} catch (Exception e) { } catch (Exception e) {

@ -5,7 +5,11 @@ import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.same.SaSameUtil; import cn.dev33.satoken.same.SaSameUtil;
import cn.dev33.satoken.util.SaResult; import cn.dev33.satoken.util.SaResult;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.core.constant.HttpStatus; import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.context.ThreadLocalHolder;
import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@ -25,7 +29,12 @@ public class SecurityConfiguration implements WebMvcConfigurer {
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
// 注册路由拦截器,自定义验证规则 // 注册路由拦截器,自定义验证规则
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); registry.addInterceptor(new SaInterceptor() {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
ThreadLocalHolder.remove(LoginHelper.LOGIN_USER_KEY);
}
}).addPathPatterns("/**");
} }
/** /**

@ -26,11 +26,6 @@
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -1,15 +1,14 @@
package org.dromara.common.tenant.helper; package org.dromara.common.tenant.helper;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.GlobalConstants; import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.context.ThreadLocalHolder;
import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.redis.utils.RedisUtils;
@ -28,7 +27,7 @@ public class TenantHelper {
private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant"; private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant";
private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>(); private static final String TENANT_ID_KEY = "tempDynamicTenant";
/** /**
* *
@ -89,12 +88,12 @@ public class TenantHelper {
return; return;
} }
if (!isLogin()) { if (!isLogin()) {
TEMP_DYNAMIC_TENANT.set(tenantId); ThreadLocalHolder.set(TENANT_ID_KEY, tenantId);
return; return;
} }
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
RedisUtils.setCacheObject(cacheKey, tenantId); RedisUtils.setCacheObject(cacheKey, tenantId);
SaHolder.getStorage().set(cacheKey, tenantId); ThreadLocalHolder.set(cacheKey, tenantId);
} }
/** /**
@ -107,15 +106,15 @@ public class TenantHelper {
return null; return null;
} }
if (!isLogin()) { if (!isLogin()) {
return TEMP_DYNAMIC_TENANT.get(); return ThreadLocalHolder.get(TENANT_ID_KEY);
} }
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
String tenantId = (String) SaHolder.getStorage().get(cacheKey); String tenantId = ThreadLocalHolder.get(cacheKey);
if (StringUtils.isNotBlank(tenantId)) { if (StringUtils.isNotBlank(tenantId)) {
return tenantId; return tenantId;
} }
tenantId = RedisUtils.getCacheObject(cacheKey); tenantId = RedisUtils.getCacheObject(cacheKey);
SaHolder.getStorage().set(cacheKey, tenantId); ThreadLocalHolder.set(cacheKey, tenantId);
return tenantId; return tenantId;
} }
@ -127,12 +126,12 @@ public class TenantHelper {
return; return;
} }
if (!isLogin()) { if (!isLogin()) {
TEMP_DYNAMIC_TENANT.remove(); ThreadLocalHolder.remove(TENANT_ID_KEY);
return; return;
} }
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId(); String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
RedisUtils.deleteObject(cacheKey); RedisUtils.deleteObject(cacheKey);
SaHolder.getStorage().delete(cacheKey); ThreadLocalHolder.remove(cacheKey);
} }
/** /**

Loading…
Cancel
Save