refactor(cache): 将Redis缓存替换为Caffeine缓存实现

修改缓存过期时间为10分钟
添加put方法到AbstractCaffeineCacheTemplate
更新相关服务类使用CaffeineCacheService
This commit is contained in:
dzq 2025-09-19 15:03:32 +08:00
parent 8eb671ec58
commit f19a8077c4
7 changed files with 32 additions and 24 deletions

View File

@ -6,7 +6,7 @@ import com.agileboot.common.core.dto.ResponseDTO;
import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode.Client; import com.agileboot.common.exception.error.ErrorCode.Client;
import com.agileboot.common.utils.ServletHolderUtil; import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.domain.common.cache.RedisCacheService; import com.agileboot.domain.common.cache.CaffeineCacheService;
import com.agileboot.admin.customize.async.AsyncTaskFactory; import com.agileboot.admin.customize.async.AsyncTaskFactory;
import com.agileboot.infrastructure.thread.ThreadPoolManager; import com.agileboot.infrastructure.thread.ThreadPoolManager;
import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.infrastructure.user.web.SystemLoginUser;
@ -48,7 +48,7 @@ public class SecurityConfig {
private final TokenService tokenService; private final TokenService tokenService;
private final RedisCacheService redisCache; private final CaffeineCacheService caffeineCache;
/** /**
* token认证过滤器 * token认证过滤器
@ -89,7 +89,7 @@ public class SecurityConfig {
if (loginUser != null) { if (loginUser != null) {
String userName = loginUser.getUsername(); String userName = loginUser.getUsername();
// 删除用户缓存记录 // 删除用户缓存记录
redisCache.loginUserCache.delete(loginUser.getCachedKey()); caffeineCache.loginUserCache.invalidate(loginUser.getCachedKey());
// 记录用户退出日志 // 记录用户退出日志
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask( ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(
userName, LoginStatusEnum.LOGOUT, LoginStatusEnum.LOGOUT.description())); userName, LoginStatusEnum.LOGOUT, LoginStatusEnum.LOGOUT.description()));

View File

@ -21,7 +21,7 @@ import com.agileboot.common.utils.ServletHolderUtil;
import com.agileboot.common.utils.i18n.MessageUtils; import com.agileboot.common.utils.i18n.MessageUtils;
import com.agileboot.domain.common.cache.GuavaCacheService; import com.agileboot.domain.common.cache.GuavaCacheService;
import com.agileboot.domain.common.cache.MapCache; import com.agileboot.domain.common.cache.MapCache;
import com.agileboot.domain.common.cache.RedisCacheService; import com.agileboot.domain.common.cache.CaffeineCacheService;
import com.agileboot.admin.customize.async.AsyncTaskFactory; import com.agileboot.admin.customize.async.AsyncTaskFactory;
import com.agileboot.domain.qywx.accessToken.AccessTokenApplicationService; import com.agileboot.domain.qywx.accessToken.AccessTokenApplicationService;
import com.agileboot.domain.qywx.accessToken.db.QyAccessTokenEntity; import com.agileboot.domain.qywx.accessToken.db.QyAccessTokenEntity;
@ -66,7 +66,7 @@ public class LoginService {
private final TokenService tokenService; private final TokenService tokenService;
private final RedisCacheService redisCache; private final CaffeineCacheService caffeineCache;
private final GuavaCacheService guavaCache; private final GuavaCacheService guavaCache;
@ -198,7 +198,8 @@ public class LoginService {
// 保存验证码信息 // 保存验证码信息
String imgKey = IdUtil.simpleUUID(); String imgKey = IdUtil.simpleUUID();
redisCache.captchaCache.set(imgKey, answer); caffeineCache.captchaCache.put(imgKey, answer);
// 转换流信息写出 // 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream(); FastByteArrayOutputStream os = new FastByteArrayOutputStream();
ImgUtil.writeJpg(image, os); ImgUtil.writeJpg(image, os);
@ -220,8 +221,8 @@ public class LoginService {
* @param captchaCodeKey 验证码对应的缓存key * @param captchaCodeKey 验证码对应的缓存key
*/ */
public void validateCaptcha(String username, String captchaCode, String captchaCodeKey) { public void validateCaptcha(String username, String captchaCode, String captchaCodeKey) {
String captcha = redisCache.captchaCache.getObjectById(captchaCodeKey); String captcha = caffeineCache.captchaCache.get(captchaCodeKey);
redisCache.captchaCache.delete(captchaCodeKey); caffeineCache.captchaCache.invalidate(captchaCodeKey);
if (captcha == null) { if (captcha == null) {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(username, LoginStatusEnum.LOGIN_FAIL, ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(username, LoginStatusEnum.LOGIN_FAIL,
ErrorCode.Business.LOGIN_CAPTCHA_CODE_EXPIRE.message())); ErrorCode.Business.LOGIN_CAPTCHA_CODE_EXPIRE.message()));
@ -242,7 +243,7 @@ public class LoginService {
ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginUser.getUsername(), LoginStatusEnum.LOGIN_SUCCESS, ThreadPoolManager.execute(AsyncTaskFactory.loginInfoTask(loginUser.getUsername(), LoginStatusEnum.LOGIN_SUCCESS,
LoginStatusEnum.LOGIN_SUCCESS.description())); LoginStatusEnum.LOGIN_SUCCESS.description()));
SysUserEntity entity = redisCache.userCache.getObjectById(loginUser.getUserId()); SysUserEntity entity = caffeineCache.userCache.get(String.valueOf(loginUser.getUserId()));
entity.setLoginIp(ServletUtil.getClientIP(ServletHolderUtil.getRequest())); entity.setLoginIp(ServletUtil.getClientIP(ServletHolderUtil.getRequest()));
entity.setLoginDate(DateUtil.date()); entity.setLoginDate(DateUtil.date());

View File

@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil;
import com.agileboot.common.constant.Constants.Token; import com.agileboot.common.constant.Constants.Token;
import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.domain.common.cache.RedisCacheService; import com.agileboot.domain.common.cache.CaffeineCacheService;
import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.infrastructure.user.web.SystemLoginUser;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
@ -54,7 +54,7 @@ public class TokenService {
@Value("${token.autoRefreshTime}") @Value("${token.autoRefreshTime}")
private long autoRefreshTime; private long autoRefreshTime;
private final RedisCacheService redisCache; private final CaffeineCacheService caffeineCache;
/** /**
* 获取用户身份信息 * 获取用户身份信息
@ -70,7 +70,7 @@ public class TokenService {
// 解析对应的权限以及用户信息 // 解析对应的权限以及用户信息
String uuid = (String) claims.get(Token.LOGIN_USER_KEY); String uuid = (String) claims.get(Token.LOGIN_USER_KEY);
return redisCache.loginUserCache.getObjectOnlyInCacheById(uuid); return caffeineCache.loginUserCache.get(uuid);
} catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException jwtException) { } catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException jwtException) {
log.error("parse token failed.", jwtException); log.error("parse token failed.", jwtException);
throw new ApiException(jwtException, ErrorCode.Client.INVALID_TOKEN); throw new ApiException(jwtException, ErrorCode.Client.INVALID_TOKEN);
@ -92,7 +92,8 @@ public class TokenService {
public String createTokenAndPutUserInCache(SystemLoginUser loginUser) { public String createTokenAndPutUserInCache(SystemLoginUser loginUser) {
loginUser.setCachedKey(IdUtil.fastUUID()); loginUser.setCachedKey(IdUtil.fastUUID());
redisCache.loginUserCache.set(loginUser.getCachedKey(), loginUser); caffeineCache.loginUserCache.put(loginUser.getCachedKey(), loginUser);
return generateToken(MapUtil.of(Token.LOGIN_USER_KEY, loginUser.getCachedKey())); return generateToken(MapUtil.of(Token.LOGIN_USER_KEY, loginUser.getCachedKey()));
} }
@ -105,8 +106,7 @@ public class TokenService {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (currentTime > loginUser.getAutoRefreshCacheTime()) { if (currentTime > loginUser.getAutoRefreshCacheTime()) {
loginUser.setAutoRefreshCacheTime(currentTime + TimeUnit.MINUTES.toMillis(autoRefreshTime)); loginUser.setAutoRefreshCacheTime(currentTime + TimeUnit.MINUTES.toMillis(autoRefreshTime));
// 根据uuid将loginUser存入缓存 caffeineCache.loginUserCache.put(loginUser.getCachedKey(), loginUser);
redisCache.loginUserCache.set(loginUser.getCachedKey(), loginUser);
} }
} }

View File

@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil;
import com.agileboot.common.constant.Constants.Token; import com.agileboot.common.constant.Constants.Token;
import com.agileboot.common.exception.ApiException; import com.agileboot.common.exception.ApiException;
import com.agileboot.common.exception.error.ErrorCode; import com.agileboot.common.exception.error.ErrorCode;
import com.agileboot.domain.common.cache.RedisCacheService; import com.agileboot.domain.common.cache.CaffeineCacheService;
import com.agileboot.infrastructure.user.web.SystemLoginUser; import com.agileboot.infrastructure.user.web.SystemLoginUser;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
@ -43,7 +43,7 @@ public class JwtTokenService {
@Value("${token.secret}") @Value("${token.secret}")
private String secret; private String secret;
private final RedisCacheService redisCache; private final CaffeineCacheService caffeineCache;
/** /**
* 获取用户身份信息 * 获取用户身份信息
@ -59,12 +59,12 @@ public class JwtTokenService {
// 解析对应的权限以及用户信息 // 解析对应的权限以及用户信息
String uuid = (String) claims.get(Token.LOGIN_USER_KEY); String uuid = (String) claims.get(Token.LOGIN_USER_KEY);
return redisCache.loginUserCache.getObjectOnlyInCacheById(uuid); return caffeineCache.loginUserCache.get(uuid);
} catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException jwtException) { } catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException jwtException) {
log.error("parse token failed.", jwtException); log.error("parse token failed.", jwtException);
throw new ApiException(jwtException, ErrorCode.Client.INVALID_TOKEN); throw new ApiException(jwtException, ErrorCode.Client.INVALID_TOKEN);
} catch (Exception e) { } catch (Exception e) {
log.error("fail to get cached user from redis", e); log.error("fail to get cached user from caffeine", e);
throw new ApiException(e, ErrorCode.Client.TOKEN_PROCESS_FAILED, e.getMessage()); throw new ApiException(e, ErrorCode.Client.TOKEN_PROCESS_FAILED, e.getMessage());
} }

View File

@ -14,7 +14,7 @@ import org.springframework.stereotype.Component;
/** /**
* 缓存中心 提供全局访问点 * 缓存中心 提供全局访问点
* 如果是领域类的缓存 可以自己新建一个直接放在CacheCenter 不用放在infrastructure包里的GuavaCacheService * 如果是领域类的缓存 可以自己新建一个直接放在CacheCenter 不用放在infrastructure包里的GuavaCacheService
* 或者RedisCacheService * 或者CaffeineCacheService
* @author valarchie * @author valarchie
*/ */
@Component @Component

View File

@ -6,7 +6,7 @@ import com.agileboot.domain.ab98.api.Ab98ApiUtil;
import com.agileboot.domain.ab98.api.SsoLoginUserinfo; import com.agileboot.domain.ab98.api.SsoLoginUserinfo;
import com.agileboot.domain.ab98.user.db.Ab98UserEntity; import com.agileboot.domain.ab98.user.db.Ab98UserEntity;
import com.agileboot.domain.ab98.user.db.Ab98UserService; import com.agileboot.domain.ab98.user.db.Ab98UserService;
import com.agileboot.domain.common.cache.RedisCacheService; import com.agileboot.domain.common.cache.CaffeineCacheService;
import com.agileboot.domain.common.command.BulkOperationCommand; import com.agileboot.domain.common.command.BulkOperationCommand;
import com.agileboot.domain.qywx.user.command.AddQyUserCommand; import com.agileboot.domain.qywx.user.command.AddQyUserCommand;
import com.agileboot.domain.qywx.user.command.UpdateQyUserCommand; import com.agileboot.domain.qywx.user.command.UpdateQyUserCommand;
@ -44,7 +44,7 @@ public class QyUserApplicationService {
private final SysRoleService sysRoleService; private final SysRoleService sysRoleService;
private final Ab98UserService ab98UserService; private final Ab98UserService ab98UserService;
private final RedisCacheService redisCache; private final CaffeineCacheService caffeineCache;
public PageDTO<QyUserDTO> getUserList(SearchQyUserQuery<QyUserEntity> query) { public PageDTO<QyUserDTO> getUserList(SearchQyUserQuery<QyUserEntity> query) {
Page<QyUserEntity> page = userService.getUserList(query); Page<QyUserEntity> page = userService.getUserList(query);
@ -104,7 +104,7 @@ public class QyUserApplicationService {
sysUser.setRoleId(command.getRoleId() > 0 ? command.getRoleId() : null); sysUser.setRoleId(command.getRoleId() > 0 ? command.getRoleId() : null);
sysUser.updateById(); sysUser.updateById();
redisCache.userCache.delete(sysUser.getUserId()); caffeineCache.userCache.invalidate(String.valueOf(sysUser.getUserId()));
} }
} }

View File

@ -27,7 +27,7 @@ public abstract class AbstractCaffeineCacheTemplate<T> {
// 设置软引用值 // 设置软引用值
.softValues() .softValues()
// 设置过期时间 - 最后一次写入后经过固定时间过期 // 设置过期时间 - 最后一次写入后经过固定时间过期
.expireAfterWrite(60, TimeUnit.MINUTES) .expireAfterWrite(10, TimeUnit.MINUTES)
// 设置刷新时间 - 写入后经过固定时间刷新 // 设置刷新时间 - 写入后经过固定时间刷新
.refreshAfterWrite(5, TimeUnit.MINUTES) .refreshAfterWrite(5, TimeUnit.MINUTES)
// 所有segment的初始总容量大小 // 所有segment的初始总容量大小
@ -74,6 +74,13 @@ public abstract class AbstractCaffeineCacheTemplate<T> {
} }
} }
public void put(String key, T value) {
if (StrUtil.isEmpty(key)) {
return;
}
caffeineCache.put(key, Optional.ofNullable(value));
}
/** /**
* 使缓存失效 * 使缓存失效
* @param key 缓存键 * @param key 缓存键