package com.pingan.haofang.agent.saas.util.cache.daemon;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
/**
* 增强型本地缓存
*/
public class DaemonCache<K,V> {
private static final Logger log = Logger.getLogger(DaemonCache.class);
/** 对Null类型的值,用户希望设定的过期时间 ,时间单位为秒 */
private long nullValueExpiredTime = 10;
/** 对于正常的缓存值,用户希望设定的过期时间,时间单位为秒 */
private long valueExpiredTime = 10;
/** 对于通过getDataByKey接口获取数据是报错的情况,用户希望Null在本地缓存的过期时间,时间单位为秒*/
private long errorValueExpiredTime = 10;
private static long LOCAL_CACHE_MAX_SIZE=100000l;
/** 默认本地缓存大小 */
private long localCacheSize= LOCAL_CACHE_MAX_SIZE;
/** 本地缓存核心,一个HashMap,最高效率读写*/
private final HashMap<K,LocalCacheValue<V>> localCache = new HashMap<K,LocalCacheValue<V>>();
/** DaemonCacheDataCallBack的实现,在创建一个DaemonCache,强制要求用户实现 */
private DaemonCacheDataCallBack<K,V> callback;
/** 需要传入daemonCacheDataCallBack构造 */
public DaemonCache(DaemonCacheDataCallBack<K,V> daemonCacheDataCallBack){
if(daemonCacheDataCallBack==null){
throw new IllegalArgumentException("when create a new DaemonCache, please implmement the DaemonCacheDataCallBack first!");
}
this.callback=daemonCacheDataCallBack;
}
/**
* 创建DaemonCache实例 ,默认本地缓存大小为10万
* @param nullValueExpiredTime 空数据过期时间
* @param valueExpiredTime 正常时间期望过期时间
* @param errorValueExpiredTime 数据接口查询错误过期时间
*/
public DaemonCache(long valueExpiredTime,long nullValueExpiredTime,long errorValueExpiredTime) {
this.valueExpiredTime = valueExpiredTime;
this.nullValueExpiredTime = nullValueExpiredTime;
this.errorValueExpiredTime = errorValueExpiredTime;
}
/**
* 创建DaemonCache实例 ,带有数据层逻辑回调实现,默认本地缓存大小为10万
* @param valueExpiredTime 空数据过期时间 ,时间单位为"秒"
* @param nullValueExpiredTime 正常时间期望过期时间,时间单位为"秒"
* @param errorValueExpiredTime 数据接口查询错误过期时间,时间单位为"秒"
* @param callback 数据层逻辑回调实现,实现自DaemonCacheDataCallBack<K, V>接口
* 例子:
* DaemonCache localCache = new DaemonCache<Integer, List<Item>>(
60,//nullValueExpiredTime 空数据过期时间
60 * 60,//valueExpiredTime 正常时间期望过期时间
60,//errorValueExpiredTime 数据接口查询错误过期时间
new DaemonCacheDataCallBack<Integer, List<Item>>() {
@Override
public List<Item> getDataByKey(Integer key) {
return getTopItemsImpl(key); //这里为业务逻辑实现
}
}
);
*/
public DaemonCache(long valueExpiredTime,long nullValueExpiredTime,
long errorValueExpiredTime,DaemonCacheDataCallBack<K, V> callback) {
if(callback==null){
throw new IllegalArgumentException("when create a new DaemonCache, please implmement the DaemonCacheDataCallBack first!");
}
this.callback=callback;
this.nullValueExpiredTime = nullValueExpiredTime;
this.valueExpiredTime = valueExpiredTime;
this.errorValueExpiredTime = errorValueExpiredTime;
}
/**
* 获取默认的DaemonCache,过期时间默认为都为10s , 默认本地缓存大小为10万
* @param daemonCacheDataCallBack 数据层逻辑回调实现,实现自DaemonCacheDataCallBack<K, V>接口
* @return DaemonCache 默认的实例
*/
public DaemonCache<K, V> getDefaultDaemonCache(DaemonCacheDataCallBack<K,V> daemonCacheDataCallBack){
if(daemonCacheDataCallBack==null){
throw new IllegalArgumentException("when create a new DaemonCache, please implmement the DaemonCacheDataCallBack first!");
}
this.callback=daemonCacheDataCallBack;
return new DaemonCache<K, V>(nullValueExpiredTime,valueExpiredTime,errorValueExpiredTime,daemonCacheDataCallBack);
}
/**
* 通过key从Cache中获取对应的Value l
* @param key <K>
* @return V value
*/
public V get(K key){
if(localCache.size()>LOCAL_CACHE_MAX_SIZE){
log.debug("0-cache已经满了,直接返回业务数据");
//判断是否cache已经满了, 如果已近满了,那么直接返回结果
try {
V callBackResult = callback.getDataByKey(key);
return callBackResult;
} catch (DaemonCacheDataCallBackException e) {
e.printStackTrace();
return null;
}
}
LocalCacheValue<V> localCacheValueResult = localCache.get(key);
if (localCacheValueResult != null) {
if (!localCacheValueResult.isExpired()) {
// ->返回正常的业务数据,此时业务数据在本地缓存中不仅存在而且没有过期
//如果Value是NUll,并且没有过期,将直接返回Null
log.debug("1-返回正常的业务数据,此时业务数据在本地缓存中不仅存在而且没有过期");
return localCacheValueResult.getValue();
}
//->数据有,但是过期
log.debug("数据有,但是过期,调用数据查询接口(下层Memcache和DB的查询逻辑)");
try {
//先调用数据查询接口(下层Memcache和DB的查询逻辑)
V callBackResult = callback.getDataByKey(key);
if(callBackResult==null){
//没有数据,向Cache中回写Null,并设定过期时间(这里的时间可能偏长)
log.debug("2-没有数据,向Cache中回写Null,并设定过期时间(这里的时间可能偏长)");
putNULL(key, this.nullValueExpiredTime);
return null;
}else {
//有数据,填充数据并设定时间(业务数据过期时间)
log.debug("3-有数据,填充数据并设定时间(业务数据过期时间)");
put(key, new LocalCacheValue<V>(callBackResult), this.valueExpiredTime);
return callBackResult;
}
} catch (DaemonCacheDataCallBackException e) {
e.printStackTrace();
//数据查询报错,向Cache中回写Null,并设定过期时间(这里的时间可能偏短)
log.debug("4-数据查询报错,向Cache中回写老数据,并设定过期时间(这里的时间可能偏短)");
put(key, localCacheValueResult, this.errorValueExpiredTime);
return localCacheValueResult.getValue();
}
}
// -> 没有数据,或者为NULL(NULL数据已经过期)
log.debug("没有数据,或者为NULL(NULL数据已经过期)");
try {
// 先调用数据查询接口(下层Memcache和DB的查询逻辑)
V callBackResult = callback.getDataByKey(key);
if (callBackResult == null) {
// 没有数据,向Cache中回写Null,并设定过期时间(这里的时间可能偏长)
log.debug("5-无数据,向Cache中回写Null,并设定过期时间(这里的时间可能偏长)");
putNULL(key, this.nullValueExpiredTime);
return null;
} else {
// 有数据,填充数据并设定时间(业务数据过期时间)
log.debug("6-有数据,填充数据并设定时间(业务数据过期时间)");
put(key, new LocalCacheValue<V>(callBackResult),this.valueExpiredTime);
return callBackResult;
}
} catch (DaemonCacheDataCallBackException e) {
e.printStackTrace();
// 数据查询报错,向Cache中回写Null,并设定过期时间(这里的时间可能偏短)
log.debug("7-数据查询报错,向Cache中回写Null,并设定过期时间(这里的时间可能偏短)");
putNULL(key, this.errorValueExpiredTime);
return null;
}
}
/**
* 向localcache中放入Null值
* @param key cache的Key
* @param expiredTime Null 值的过期时间
*/
private void putNULL(K key, long expiredTime) {
LocalCacheValue<V> nullValue = new LocalCacheValue<V>();
nullValue.setNullValue(true);
put(key, nullValue , expiredTime);
}
/**
* 向Cache中放入key和Value,需要指定过期时间
* @param key
* @param value
* @param expiredTime
*/
private void put(K key, LocalCacheValue<V> value , long expiredTime) {
expiredTime = TimeUnit.NANOSECONDS.convert(expiredTime,TimeUnit.SECONDS );
value.setExpiredTime(expiredTime);
value.setExpiredStartTime(System.nanoTime());
localCache.put(key, value);
}
/**
* 注入对应的业务回调实例
* @param callback 数据层逻辑回调实现,实现自DaemonCacheDataCallBack<K, V>接口
*/
public void setCallback(DaemonCacheDataCallBack<K, V> callback) {
if (callback == null) {
throw new IllegalArgumentException(
"the callback is null here , please check !");
}
this.callback = callback;
}
/**
* 清空本地缓存
*/
public void clearLocalCache(){
this.localCache.clear();
}
/**
* 设置本地cache大小,本地cache的最大值不得高于10万,默认本地缓存大小为10万
* @param localCacheSize
*/
public void setLocalCacheSize(long localCacheSize) {
if (localCacheSize<=0||localCacheSize>LOCAL_CACHE_MAX_SIZE) {
throw new IllegalArgumentException(
"the local cache size must be less then the max :"+LOCAL_CACHE_MAX_SIZE);
}
this.localCacheSize = localCacheSize;
}
}
分享到:
相关推荐
WriteCache方法: 用Dictionary, Dictionary, byte[]>替代Cache类 数据库名+表名 为缓存KEY SQL语句为缓存键值的key 查询结果序列化为缓存键值的Values 序列化后加密保存在本地供调用 ReadCache方法:解密后反序列...
用Dictionary, Dictionary, byte[]>替代Cache类 数据库名+表名 为缓存KEY SQL语句为缓存键值的key 查询结果序列化为缓存键值的Values 序列化后加密保存在本地供调用 ReadCache方法:等分不够了再写。
Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~
redis本地缓存与redis缓存
本篇文章主要介绍了Java中LocalCache本地缓存实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
主要涉及本地缓存与分布式缓存优缺点,使用,前部宣讲
JS localStorage实现本地缓存的方法,需要的朋友可以参考一下
tianditu.js 天地图本地缓存4.0下载
基于java的map和timer实现本地缓存及定时清理失效缓存的功能 本项目仅用于初学者学习使用 初学者可基于此项目初步了解缓存实现的基本原理 后期在项目中使用建议使用现成的缓存框架:redis、ehcache等
图片本地缓存工具类可以直接使用,对于图片的压缩,缓存,调用,缓存清理等。
ReactNative网路及本地缓存 Fetch之get请求数据, Fetch之Post请求数据, AsyncStorageDemo本地缓存数据
使用sqlite数据库本地缓存
C#文件缓存类,可以缓存文件到本地,提升读取速度。
listview展示的新闻类,上拉加载下拉刷新+本地缓存+简单的头尾布局
清空本地DNS缓存的几种方法,亲测,可行
Caffeine本地缓存的配置与使用
avplayer边下边播本地缓存
远景本地缓存iscsicache远景本地缓存iscsicache远景本地缓存iscsicache
继承重写SafeKeyGenerator类,做到替换默认加密算法从SHA256到MD5,从而可以通过图片url的md5去查寻已经下载到本地的缓存文件