`

本地缓存类

 
阅读更多
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

    java本地缓存ConcurrentHashMap

    c# 完整本地缓存类

    WriteCache方法: 用Dictionary, Dictionary, byte[]&gt;替代Cache类 数据库名+表名 为缓存KEY SQL语句为缓存键值的key 查询结果序列化为缓存键值的Values 序列化后加密保存在本地供调用 ReadCache方法:解密后反序列...

    c# 本地缓存类

    用Dictionary, Dictionary, byte[]&gt;替代Cache类 数据库名+表名 为缓存KEY SQL语句为缓存键值的key 查询结果序列化为缓存键值的Values 序列化后加密保存在本地供调用 ReadCache方法:等分不够了再写。

    本地缓存与分布式缓存优缺点,使用

    本地缓存与分布式缓存优缺点、使用场景 缓存是计算机系统中的一种优化技术,通过将频繁访问的数据存储在内存中,以减少对外部存储设备的访问次数,提高系统的响应速度和性能。本文将详细介绍本地缓存与分布式缓存的...

    Java利用ConcurrentHashMap实现本地缓存demo

    Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~

    redis本地缓存与redis缓存

    在“redis本地缓存与redis缓存”的主题中,我们将深入探讨这两种缓存方式及其各自的特点。 首先,我们要理解什么是本地缓存。本地缓存指的是将数据存储在应用程序的内存中,通常是Java的HashMap、Guava Cache或C#的...

    带有本地缓存机制的http连接框架

    它可以将从服务器获取的数据存储在设备的本地存储(如SQLite数据库、文件系统或内存)中,当用户再次请求相同数据时,可以优先从本地缓存读取,避免了不必要的网络延迟,提高了应用的响应速度。 1. 数据缓存策略:...

    springboot本地缓存(guava与caffeine).docx

    Spring Boot 本地缓存(Guava 与 Caffeine) Spring Boot 中的本地缓存是指在应用程序中存储和检索数据的机制,以提高应用程序的性能和响应速度。在本地缓存中,我们可以使用 Guava 或 Caffeine 等库来实现缓存...

    android本地缓存

    在Android开发中,本地缓存是一种常见的技术,用于提高应用性能和用户体验。本地缓存能够减少网络请求,避免频繁的数据加载,特别是在用户离线时也能访问之前加载过的数据。本篇文章将详细介绍Android本地缓存的基本...

    tianditu.js 天地图本地缓存4.0下载

    tianditu.js 天地图本地缓存4.0下载

    PB SQL 缓存数据到本地 类

    通常,这类缓存机制会包含数据的加载、更新和同步逻辑,以确保本地缓存与远程服务器上的数据保持一致。 在实现这个功能时,开发者可能需要考虑以下几点: 1. **数据选择**:确定哪些数据需要被缓存。通常是那些...

    java手写本地缓存示例

    基于java的map和timer实现本地缓存及定时清理失效缓存的功能 本项目仅用于初学者学习使用 初学者可基于此项目初步了解缓存实现的基本原理 后期在项目中使用建议使用现成的缓存框架:redis、ehcache等

    MAC版本outlook本地缓存路径

    ### MAC版本Outlook本地缓存路径详解 #### 一、Outlook for Mac 介绍 Microsoft Outlook for Mac 是一款由微软公司开发的专业电子邮件客户端与个人信息管理软件,它为Mac用户提供了与Windows版本相媲美的功能体验...

    延时加载+静态资源本地缓存

    "延时加载+静态资源本地缓存"是两种非常有效的技术手段,它们能够帮助我们实现这一目标。本篇文章将详细探讨这两种策略,以及如何将它们应用于实际项目中。 首先,让我们来看看静态资源本地缓存。静态资源通常包括...

    ReactNative网路及本地缓存

    在这个“ReactNative网路及本地缓存”的主题中,我们将深入探讨如何在ReactNative应用中处理网络请求以及本地数据存储。 首先,我们来看网络请求部分,主要涉及Fetch API的使用。Fetch是一个现代的、基于Promise的...

    清空本地DNS缓存

    ### 清空本地DNS缓存的方法 在计算机网络中,DNS(Domain Name System,域名系统)扮演着将网站域名转换为IP地址的重要角色。为了提高访问速度和效率,操作系统会缓存这些DNS查询结果,即DNS缓存。然而,在某些情况...

    winform简单缓存类实例

    本文将深入探讨如何在WinForm应用中实现一个简单的缓存类,主要基于System.Web.Caching命名空间中的Cache对象。这个缓存类可以帮助我们存储数据,避免频繁地从数据库中读取,从而提高应用程序的响应速度。 首先,...

    iscsi本地缓存(支持多盘符)

    **ISCSI本地缓存技术详解** ISCSI(Internet Small Computer System Interface)是一种基于TCP/IP协议的存储网络协议,它允许网络设备通过IP网络传输SCSI命令,实现存储设备的远程访问。ISCSI本地缓存技术是针对...

Global site tag (gtag.js) - Google Analytics