使用ConcurrentHashMap 设置Cookie
上篇说到将Cookie 存到HttpServletResponse中,前端缓存的形式。现在将cookie缓存至内存。
使用ConcurrentHashMap结合LinkedList的形式,将cookie缓存。
1.先设置cookie类。
public class CookieObj {
/**
* 缓存对象
*/
private Object cacheValue;
/**
* 设置过期时间
*/
private Long ttlTime;
public CookieObj() {
}
public CookieObj(Object cacheValue, long ttlTime) {
this.cacheValue = cacheValue;
this.ttlTime = ttlTime;
}
public Object getCacheValue() {
return cacheValue;
}
public void setCacheValue(Object cacheValue) {
this.cacheValue = cacheValue;
}
public Long getTtlTime() {
return ttlTime;
}
public void setTtlTime(Long ttlTime) {
this.ttlTime = ttlTime;
}
@Override
public String toString() {
return "CookieObj{" +
"cacheValue=" + cacheValue +
", ttlTime=" + ttlTime +
'}';
}
}
2 设置cookie
/**
* @description: Cookie缓存工具类
* @author: Lina
* @create: 2020-11-24 19:38
*/
public class CookieUtils {
private static Logger LOGGER = LoggerFactory.getLogger(CookieUtils.class);
/**
* 最大缓存数量
*/
private static final Integer COOKIE_MAX = 1000;
/**
* 当前缓存个数
*/
private static Integer CURRENT_SIZE = 0;
/**
* 设置清除定时时长为3h
*/
static final Long CLEAR_TIME = 3 * 60 * 60 * 1000L;
/**
* 设置在线时长为2h
*/
static final Long ONLINE_TIME = 2 * 60 * 60 * 1000L;
/**
* 清理过期缓存是否在运行
*/
private static volatile Boolean CLEAN_THREAD_IS_RUN = false;
/**
* 缓存对象
*/
private static final Map<String, CookieObj> COOKIE_MAP = new ConcurrentHashMap<>();
/**
* 最近使用的
*/
private static final List<String> COOKIE_USE_LOG_LIST = new LinkedList<>();
/**
* 设置缓存cookie
*
* @param cookieKey
* @param cookieValue
*/
public static void setCookie(String cookieKey, Object cookieValue) {
Long ttlTime = null;
checkSize();
saveCookieUseLog(cookieKey);
CURRENT_SIZE = CURRENT_SIZE + 1;
if (ttlTime == null) {
ttlTime = System.currentTimeMillis() + ONLINE_TIME; //设置cookie时长
}
CookieObj cookieObj = new CookieObj(cookieValue, ttlTime);
COOKIE_MAP.put(cookieKey, cookieObj);
LOGGER.info("设置的cookieKey为 :" + cookieKey);
}
/**
* 通过key 获取cookie值
*
* @param cookieKey
* @return
*/
public static String getCookie(String cookieKey) {
startCleanCookieThread();
if (checkCookie(cookieKey)) {
saveCookieUseLog(cookieKey);
LOGGER.info("获取到的cookie值为:" + COOKIE_MAP.get(cookieKey).getCacheValue().toString());
return COOKIE_MAP.get(cookieKey).getCacheValue().toString();
}
return null;
}
/**
* 保存缓存的使用记录,用Linked保存一个cookie,后续用来处理过期的cookie
*
* @param cookieKey
*/
private static void saveCookieUseLog(String cookieKey) {
synchronized (COOKIE_USE_LOG_LIST) {
COOKIE_USE_LOG_LIST.remove(cookieKey);
COOKIE_USE_LOG_LIST.add(0, cookieKey);
}
}
/**
* 判断
*
* @param cookieKey
* @return
*/
public static boolean isExist(String cookieKey) {
return checkCookie(cookieKey);
}
/**
* 检查缓存是否存在,检查是否过期
* @param cookieKey
* @return
*/
private static boolean checkCookie(String cookieKey) {
CookieObj cookieObj = COOKIE_MAP.get(cookieKey);
if (cookieObj == null) {
return false;
}
if (cookieObj.getTtlTime() == -1L) {
return true;
}
if (cookieObj.getTtlTime() < System.currentTimeMillis()) {
deleteCookie(cookieKey);
return false;
}
return true;
}
/**
* 删除过期Cookie
*
* @param cookieKey
* @return
*/
private static void deleteCookie(String cookieKey) {
Object cookieObj = COOKIE_MAP.remove(cookieKey);
if (cookieObj != null) {
LOGGER.info("删除过期Cookie" + cookieKey);
CURRENT_SIZE = CURRENT_SIZE - 1;
}
}
/**
* 删除所有缓存的Cookie
*/
static void clearAll() {
COOKIE_MAP.clear();
CURRENT_SIZE = 0;
LOGGER.info("清除所有缓存的Cookie");
}
/**
* 检查Cookie个数
*/
private static void checkSize() {
// 若超过限制,则清除过期的cookie
if (CURRENT_SIZE >= COOKIE_MAX) {
deleteTimeOut();
}
if (CURRENT_SIZE >= COOKIE_MAX) {
deleteLru();
}
}
/**
* 删除最近最久未用的cookie
*/
private static void deleteLru() {
String cookieKey = null;
synchronized (COOKIE_USE_LOG_LIST) {
if (COOKIE_USE_LOG_LIST.size() >= COOKIE_MAX - 10) {
cookieKey = COOKIE_USE_LOG_LIST.remove(COOKIE_USE_LOG_LIST.size() - 1);
}
}
if (cookieKey != null) {
deleteCookie(cookieKey);
}
LOGGER.info("删除最近最久未用的cookie");
}
/**
* 清除过期的cookie
*/
static void deleteTimeOut() {
LOGGER.info("clear timeOut cookie:");
List<String> deleteList = new LinkedList<>();
for (Map.Entry<String, CookieObj> entry : COOKIE_MAP.entrySet()) {
if (entry.getValue().getTtlTime() < System.currentTimeMillis() && entry.getValue().getTtlTime() != -1L) {
deleteList.add(entry.getKey());
}
}
// 将过期的Cookie删除
for (String deleteKey : deleteList) {
deleteCookie(deleteKey);
}
LOGGER.info("已删除cookie条数:" + deleteList.size());
}
/**
* 设置清理线程的运行状态为正在运行
*/
static void setCleanThreadRun() {
CLEAN_THREAD_IS_RUN = true;
}
private static void startCleanCookieThread() {
if (!CLEAN_THREAD_IS_RUN) {
CleanOutLineThread cleanOutLineThread = new CleanOutLineThread();
Thread thread = new Thread(cleanOutLineThread);
thread.setName("清除Cookie的线程");
thread.setDaemon(true);
thread.start();
}
}
}
class CleanOutLineThread implements Runnable {
private static Logger LOGGER = LoggerFactory.getLogger(CleanOutLineThread.class);
@Override
public void run() {
CookieUtils.setCleanThreadRun();
while (true) {
LOGGER.info("开始清除过期cookie");
CookieUtils.deleteTimeOut();
try {
Thread.sleep(CookieUtils.CLEAR_TIME);
} catch (Exception e) {
LOGGER.error("清除过期cookie出错");
}
}
}
}
以上是使用ConcurrentHashMap缓存cookie的方法。期间使用的LinkedList也需要synchronized关键字,同步代码快,来保证线程竞争问题,保证在多线程的环境下,安全使用。