package com.doumee.core.cache;
|
|
import lombok.Data;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang3.SerializationUtils;
|
import org.springframework.stereotype.Component;
|
|
import java.io.Serializable;
|
import java.util.*;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* 单机本地缓存,项目初始阶段使用
|
* - 超过指定大小可通过日志方式报警
|
* - 延长超时时间
|
* @author Eva.Caesar Liu
|
* @date 2019/3/23 17:57
|
*/
|
@Slf4j
|
@Component
|
public final class LocalCache<K,V> {
|
|
// 警告大小
|
private final int WARN_SIZE = 1073741824;
|
|
// GB大小
|
private final int GB_SIZE = 1073741824;
|
|
// 缓存实例
|
private static LocalCache instance;
|
|
// 数据存储对象
|
private ConcurrentHashMap<K, Value<V>> cache = new ConcurrentHashMap();
|
|
private LocalCache(){}
|
|
public static LocalCache getInstance() {
|
if(instance == null) {
|
synchronized (LocalCache.class) {
|
if(instance == null)
|
instance = new LocalCache();
|
}
|
}
|
return instance;
|
}
|
|
/**
|
* 添加缓存,超时时间为30分钟
|
* @param key 缓存键
|
* @param value 缓存值
|
*/
|
public void put(K key, V value) {
|
Value<V> v = cache.get(key);
|
if (v != null) {
|
v.value = value;
|
return;
|
}
|
put(key, value, 30 * 60 * 1000);
|
}
|
|
/**
|
* 添加缓存
|
* @param key 缓存键
|
* @param value 缓存值
|
* @param timeout 超时时间
|
*/
|
public void put(K key, V value, long timeout) {
|
if(key == null) throw new NullPointerException("key can not be null");
|
// 清理旧数据
|
long now = System.currentTimeMillis();
|
for(Map.Entry<K, Value<V>> entry: cache.entrySet()){
|
Value v = entry.getValue();
|
if(v.getValue() == null) // 值为空时清除掉
|
cache.remove(entry.getKey());
|
if(now - v.getBirthtime() > v.getTimeout()) // 超时时清除掉
|
cache.remove(entry.getKey());
|
}
|
|
// 添加缓存
|
Value<V> v = new Value<>();
|
v.setBirthtime(now);
|
v.setTimeout(timeout);
|
v.setValue(value);
|
cache.put(key, v);
|
|
// 获取对象大小,超过一定大小打印警告
|
int cacheSize = SerializationUtils.serialize(cache).length;
|
if(cacheSize > WARN_SIZE) {
|
log.warn("本地缓存已超过{}G,当前缓存容量为:{}G", (double) Math.round((double) WARN_SIZE / GB_SIZE * 100) / 100, (double) Math.round((double) cacheSize / GB_SIZE * 100) / 100);
|
}
|
}
|
|
/**
|
* 根据key获取缓存对象
|
* @param key 缓存键
|
*/
|
public V get(K key) {
|
if(key == null) return null;
|
Value<V> value = cache.get(key);
|
if(value == null)
|
return null;
|
if(value.getValue() == null)
|
return null;
|
if(System.currentTimeMillis() - value.getBirthtime() > value.getTimeout()) {
|
remove(key);
|
return null;
|
}
|
return value.getValue();
|
}
|
|
/**
|
* 根据key获取缓存对象
|
* @param key 缓存键
|
*
|
* @return V
|
*/
|
public V remove(K key) {
|
if(key == null) return null;
|
Value<V> value = cache.get(key);
|
if (value == null) {
|
return null;
|
}
|
cache.remove(key);
|
return value.value;
|
}
|
|
/**
|
* 清空缓存
|
*/
|
public void clear () {
|
cache.clear();
|
}
|
|
/**
|
* 获取缓存数
|
*/
|
public int size () {
|
return cache.size();
|
}
|
|
/**
|
* 获取缓存所有的key
|
*/
|
public Set<K> keys () {
|
return cache.keySet();
|
}
|
|
/**
|
* 获取缓存值
|
*/
|
public Collection<V> values () {
|
Collection<Value<V>> values = cache.values();
|
List<V> vs = new ArrayList(keys().size());
|
for (Value<V> v : values) {
|
if (v.value != null) {
|
vs.add(v.value);
|
}
|
}
|
return vs;
|
}
|
|
/**
|
* 重置缓存诞生时间
|
* @param key 缓存键
|
*/
|
public void relive(String key) {
|
if (key == null) return;
|
Value v = cache.get(key);
|
if (v == null) {
|
return;
|
}
|
v.setBirthtime(new Date().getTime());
|
}
|
|
@Data
|
private static class Value<V> implements Serializable {
|
|
// 缓存具体值
|
private V value;
|
|
// 存储时间
|
private long birthtime;
|
|
// 超时时间
|
private long timeout;
|
}
|
|
}
|