java创建本地缓存模拟redis缓存操作
时间:2022-07-26
本文章向大家介绍java创建本地缓存模拟redis缓存操作,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
java创建本地缓存,模拟redis的使用
在一般的小项目中,数据量不大.但是有的时候需要使用缓存记录一些标识或者票据之类的,比如我这边想实现,可以记录系统同时在线的用户数据,或者对其他数据的缓存记录,减少DBA
请求
1. 创建缓存实体类
package com.adingxiong.cft.entity;
import java.io.Serializable;
/**
* @author xiongc
* @date 2020/07/28
*/
public class CacheEntity implements Serializable {
private static final long serialVersionUID = -107853226360392750L;
/**
* 值
*/
private Object value;
/**
* 保存的时间戳
*/
private long gmtModify;
/**
* 过期时间
*/
private int expire;
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
public long getGmtModify() {
return gmtModify;
}
public void setGmtModify(long gmtModify) {
this.gmtModify = gmtModify;
}
public int getExpire() {
return expire;
}
public void setExpire(int expire) {
this.expire = expire;
}
public CacheEntity(Object value, long gmtModify, int expire) {
super();
this.value = value;
this.gmtModify = gmtModify;
this.expire = expire;
}
}
2. 创建本地缓存工具类
package com.adingxiong.cft.cache;
import com.adingxiong.cft.entity.CacheEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import java.io.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @ClassName LocalCache
* @Description 本地缓存 代替redis 实现简单数据记录
* @Author xiongchao
* @Date 2020/7/28 16:14
**/
public class LocalCache {
private static final Logger log = LoggerFactory.getLogger(LocalCache.class);
/**
* 默认的缓存容量
*/
private static final int DEFAULT_CAPACITY = 512;
/**
* 最大容量
*/
private static final int MAX_CAPACITY = 100000;
/**
* 刷新缓存的频率
*/
private static final int MONITOR_DURATION = 2;
// 启动监控线程
static {
new Thread(new TimeoutTimerThread()).start();
}
// 内部类方式实现单例
private static class LocalCacheInstance{
private static final LocalCache INSTANCE=new LocalCache();
}
public static LocalCache getInstance() {
return LocalCacheInstance.INSTANCE;
}
private LocalCache() {
}
/**
* 使用默认容量创建一个Map
*/
private static Map<String, CacheEntity> cache = new ConcurrentHashMap<>(DEFAULT_CAPACITY);
/**
* 将key-value 保存到本地缓存并制定该缓存的过期时间
*
* @param key
* @param value
* @param expireTime 过期时间,如果是-1 则表示永不过期
* @return
*/
public <T> boolean putValue(String key, T value, int expireTime) {
return putCloneValue(key, value, expireTime);
}
/**
* 将值通过序列化clone 处理后保存到缓存中,可以解决值引用的问题
*
* @param key
* @param value
* @param expireTime
* @return
*/
private <T> boolean putCloneValue(String key, T value, int expireTime) {
try {
if (cache.size() >= MAX_CAPACITY) {
return false;
}
// 序列化赋值
CacheEntity entityClone = clone(new CacheEntity(value, System.nanoTime(), expireTime));
cache.put(key, entityClone);
return true;
} catch (Exception e) {
log.error("添加缓存失败:{}", e.getMessage());
}
return false;
}
/**
* 序列化 克隆处理
*
* @param object
* @return
*/
private <E extends Serializable> E clone(E object) {
E cloneObject = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
cloneObject = (E) ois.readObject();
ois.close();
} catch (Exception e) {
log.error("缓存序列化失败:{}", e.getMessage());
}
return cloneObject;
}
/**
* 从本地缓存中获取key对应的值,如果该值不存则则返回null
*
* @param key
* @return
*/
public Object getValue(String key) {
if(CollectionUtils.isEmpty(cache)){
return null;
}
return cache.get(key).getValue();
}
/**
* 清空所有
*/
public void clear() {
cache.clear();
}
/**
* 过期处理线程
*/
static class TimeoutTimerThread implements Runnable {
@Override
public void run() {
while (true) {
try {
TimeUnit.SECONDS.sleep(MONITOR_DURATION);
checkTime();
} catch (Exception e) {
log.error("过期缓存清理失败:{}", e.getMessage());
}
}
}
/**
* 过期缓存的具体处理方法
*
* @throws Exception
*/
private void checkTime() throws Exception {
// 开始处理过期
for (String key : cache.keySet()) {
CacheEntity tce = cache.get(key);
long timoutTime = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - tce.getGmtModify());
// 过期时间 : timoutTime
if (tce.getExpire() > timoutTime) {
continue;
}
log.info(" 清除过期缓存 : " + key);
//清除过期缓存和删除对应的缓存队列
cache.remove(key);
}
}
}
}
3. 测试
写一个简单的controller
@GetMapping("/cache")
public Object testCache(String name){
Object a = LocalCache.getInstance().getValue("name");
if(a == null){
LocalCache.getInstance().putValue("name" ,"张三",10);
return "未读取到缓存数据";
}
return "读取到缓存数据,数据为:" + a;
}
第一次调用
第二次调用
同时服务那边会根据你设定的过期时间去定期启动线程清理缓存数据
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php遍历目录&删除指定文件中指定内容
- pow函数问题
- 字节序列操作函数
- 3分钟短文:Laravel是怎么发出一封电子邮件的?
- Elasticsearch 设计模式
- Spring 的 WebSecurityConfigurerAdapter 过滤器
- 03.视频播放器Api说明
- Postfix配置Gmail中继发信
- 使用Syncthing自建私有同步盘
- 05.视频播放器内核切换封装
- sklearn做特征选择
- ResilioSync:公私兼备的同步盘
- 面向对象语言的三大特征: 封装 继承 多态(二)——继承
- 教你如何设置宝塔面板 Brotli压缩
- Message: session not created: This version of ChromeDriver only supports Chrome version 83