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;
}
}
分享到:
相关推荐
java本地缓存ConcurrentHashMap
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的HashMap、Guava Cache或C#的...
它可以将从服务器获取的数据存储在设备的本地存储(如SQLite数据库、文件系统或内存)中,当用户再次请求相同数据时,可以优先从本地缓存读取,避免了不必要的网络延迟,提高了应用的响应速度。 1. 数据缓存策略:...
Spring Boot 本地缓存(Guava 与 Caffeine) Spring Boot 中的本地缓存是指在应用程序中存储和检索数据的机制,以提高应用程序的性能和响应速度。在本地缓存中,我们可以使用 Guava 或 Caffeine 等库来实现缓存...
在Android开发中,本地缓存是一种常见的技术,用于提高应用性能和用户体验。本地缓存能够减少网络请求,避免频繁的数据加载,特别是在用户离线时也能访问之前加载过的数据。本篇文章将详细介绍Android本地缓存的基本...
tianditu.js 天地图本地缓存4.0下载
通常,这类缓存机制会包含数据的加载、更新和同步逻辑,以确保本地缓存与远程服务器上的数据保持一致。 在实现这个功能时,开发者可能需要考虑以下几点: 1. **数据选择**:确定哪些数据需要被缓存。通常是那些...
基于java的map和timer实现本地缓存及定时清理失效缓存的功能 本项目仅用于初学者学习使用 初学者可基于此项目初步了解缓存实现的基本原理 后期在项目中使用建议使用现成的缓存框架:redis、ehcache等
### MAC版本Outlook本地缓存路径详解 #### 一、Outlook for Mac 介绍 Microsoft Outlook for Mac 是一款由微软公司开发的专业电子邮件客户端与个人信息管理软件,它为Mac用户提供了与Windows版本相媲美的功能体验...
"延时加载+静态资源本地缓存"是两种非常有效的技术手段,它们能够帮助我们实现这一目标。本篇文章将详细探讨这两种策略,以及如何将它们应用于实际项目中。 首先,让我们来看看静态资源本地缓存。静态资源通常包括...
在这个“ReactNative网路及本地缓存”的主题中,我们将深入探讨如何在ReactNative应用中处理网络请求以及本地数据存储。 首先,我们来看网络请求部分,主要涉及Fetch API的使用。Fetch是一个现代的、基于Promise的...
### 清空本地DNS缓存的方法 在计算机网络中,DNS(Domain Name System,域名系统)扮演着将网站域名转换为IP地址的重要角色。为了提高访问速度和效率,操作系统会缓存这些DNS查询结果,即DNS缓存。然而,在某些情况...
本文将深入探讨如何在WinForm应用中实现一个简单的缓存类,主要基于System.Web.Caching命名空间中的Cache对象。这个缓存类可以帮助我们存储数据,避免频繁地从数据库中读取,从而提高应用程序的响应速度。 首先,...
**ISCSI本地缓存技术详解** ISCSI(Internet Small Computer System Interface)是一种基于TCP/IP协议的存储网络协议,它允许网络设备通过IP网络传输SCSI命令,实现存储设备的远程访问。ISCSI本地缓存技术是针对...