JAVA 实现本地缓存(可直接复用)
本来想上传上去给大家要用积分下载的,后来想想算了,给大家直接免费用吧
网上的闲杂的代码太多,所以集成了一下,这个本人已经测试过,完成可以用,一共是两个类,一个是LocalCache,另外一个是CacheEntity
LocalCache 类(主类) ,实现本地缓存的主体
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @ClassName LocalCache
* @Description
* @Author
* @Date
* @Version 1.0
*/
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 过期时间
* @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;
}
// 序列化赋值 license缓存是直接加入object所以序列化克隆不需要
CacheEntity entityClone = 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 (cache.get(key) == null){
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);
}
}
}
}
----------------------------------------------------------------------------------------------------------------------------------------
CacheEntity类
import lombok.Data;
import java.io.Serializable;
@Data
public class CacheEntity implements Serializable {
private static final long serialVersionUID = 2594373766348228819L;
/**
* 值
*/
private Object value;
/**
* 保存的时间戳
*/
private long gmtModify;
/**
* 过期时间
*/
private int expire;
public CacheEntity(Object value, long gmtModify, int expire) {
super();
this.value = value;
this.gmtModify = gmtModify;
this.expire = expire;
}
}
@Data 是lombok的注解,大家可以直接用get,set解决,这我就懒得写
下面写几个示例
LocalCache localCache = LocalCache.getInstance(); //初始化本地缓存
LicenseVO license = (LicenseVO)localCache.getValue(CacheKey.LICENSE); //根据本地缓存自定义的名称获取
localCache.putValue(CacheKey.LICENSE,license,0); //永不过期,放入缓存的参数
基本这几个方法,大部分的业务代码都能搞了。就这,谢谢大家。