package com.pingan.haofang.agent.saas.util.cache.redis; import com.pingan.haofang.agent.saas.common.utils.Log; import com.pingan.haofang.agent.saas.common.utils.RedisUtils; import org.apache.log4j.Logger; import org.springframework.data.redis.core.RedisTemplate; import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; /** * redis缓存 * */ public class RedisCache<K, V> { private static final Logger log = Logger.getLogger(RedisCache.class); private static final ExecutorService executor = Executors.newCachedThreadPool(); /** * 对Null类型的值,用户希望设定的过期时间 ,时间单位为秒 */ private long nullValueExpiredTime = 10; /** 对于正常的缓存值,用户希望设定的过期时间,时间单位为秒 */ private long valueExpiredTime = 24 * 60 * 60; /** * 对于通过getDataByKey接口获取数据是报错的情况,用户希望Null在本地缓存的过期时间,时间单位为秒 */ private long errorValueExpiredTime = 10; /** * RedisCacheDataCallBack的实现,在创建一个DaemonCache,强制要求用户实现 */ private RedisCacheDataCallBack<K, V> callback; private RedisTemplate<String, V> redisTemplate; private RedisUtils redisUtils; //private RedisUtils<K,V> redisUtils; /** * 需要传入RedisCacheDataCallBack构造 */ public RedisCache(RedisCacheDataCallBack<K, V> redisCacheDataCallBack, RedisTemplate<String, V> redisTemplate) { if (redisCacheDataCallBack == null) { throw new IllegalArgumentException("when create a new RedisCache, please implmement the RedisCacheDataCallBack first!"); } this.callback = redisCacheDataCallBack; this.redisTemplate = redisTemplate; } /** * 需要传入RedisCacheDataCallBack构造 */ public RedisCache(RedisCacheDataCallBack<K, V> redisCacheDataCallBack, RedisUtils redisUtils) { if (redisCacheDataCallBack == null) { throw new IllegalArgumentException("when create a new RedisCache, please implmement the RedisCacheDataCallBack first!"); } this.callback = redisCacheDataCallBack; this.redisUtils = redisUtils; } /** * 创建RedisCache实例 ,默认本地缓存大小为10万 * * @param nullValueExpiredTime 空数据过期时间 * @param valueExpiredTime 正常时间期望过期时间 * @param errorValueExpiredTime 数据接口查询错误过期时间 */ public RedisCache(long valueExpiredTime, long nullValueExpiredTime, long errorValueExpiredTime) { this.valueExpiredTime = valueExpiredTime; this.nullValueExpiredTime = nullValueExpiredTime; this.errorValueExpiredTime = errorValueExpiredTime; } /** * 创建RedisCache实例 ,带有数据层逻辑回调实现,默认本地缓存大小为10万 * * @param valueExpiredTime 空数据过期时间 ,时间单位为"秒" * @param nullValueExpiredTime 正常时间期望过期时间,时间单位为"秒" * @param errorValueExpiredTime 数据接口查询错误过期时间,时间单位为"秒" * @param callback 数据层逻辑回调实现,实现自RedisCacheDataCallBack<K, V>接口 * 例子: * RedisCache localCache = new RedisCache<Integer, List<Item>>( * 60,//nullValueExpiredTime 空数据过期时间 * 60 * 60,//valueExpiredTime 正常时间期望过期时间 * 60,//errorValueExpiredTime 数据接口查询错误过期时间 * new RedisCacheDataCallBack<Integer, List<Item>>() { * @Override public List<Item> getDataByKey(Integer key) { * return getTopItemsImpl(key); //这里为业务逻辑实现 * } * } * ); */ public RedisCache(long valueExpiredTime, long nullValueExpiredTime, long errorValueExpiredTime, RedisCacheDataCallBack<K, V> callback) { if (callback == null) { throw new IllegalArgumentException("when create a new RedisCache, please implmement the RedisCacheDataCallBack first!"); } this.callback = callback; this.nullValueExpiredTime = nullValueExpiredTime; this.valueExpiredTime = valueExpiredTime; this.errorValueExpiredTime = errorValueExpiredTime; } /** * 获取默认的RedisCache,过期时间默认为都为10s , 默认本地缓存大小为10万 * * @param redisCacheDataCallBack 数据层逻辑回调实现,实现自RedisCacheDataCallBack<K, V>接口 * @return RedisCache 默认的实例 */ public RedisCache<K, V> getDefaultRedisCache(RedisCacheDataCallBack<K, V> redisCacheDataCallBack) { if (redisCacheDataCallBack == null) { throw new IllegalArgumentException("when create a new RedisCache, please implmement the RedisCacheDataCallBack first!"); } this.callback = redisCacheDataCallBack; return new RedisCache<K, V>(nullValueExpiredTime, valueExpiredTime, errorValueExpiredTime, redisCacheDataCallBack); } /** * 通过key从redis中获取对应的Value l * * @param key <K> * @return V value */ public V get(String key, K k) { return get(key,k,valueExpiredTime); } public V get(String key, K k, long expireTime) { V result = (V) redisUtils.get(key); if (result != null) { return result; } // -> 没有数据,或者为NULL(NULL数据已经过期) log.debug("没有数据,或者为NULL(NULL数据已经过期)"); try { // 先调用数据查询接口(下层Memcache和DB的查询逻辑) V callBackResult = callback.getRedisDataByKey(k); if (callBackResult == null) { // 没有数据 log.debug("5-无数据"); put(key, callBackResult, this.nullValueExpiredTime); return null; } else { // 有数据,填充数据并设定时间(业务数据过期时间) log.debug("6-有数据,填充数据并设定时间(业务数据过期时间)"); put(key, callBackResult, expireTime); return callBackResult; } } catch (RedisCacheDataCallBackException e) { e.printStackTrace(); // 数据查询报错,向Cache中回写Null,并设定过期时间(这里的时间可能偏短) log.debug("7-数据查询报错"); putNULL(key, this.nullValueExpiredTime); return null; } } /** * 向localcache中放入Null值 * * @param key cache的Key * @param expiredTime Null 值的过期时间 */ private void putNULL(String key, long expiredTime) { redisTemplate.opsForValue().set(key, null, expiredTime); } /** * 向Cache中放入key和Value,需要指定过期时间 * * @param key * @param value * @param expiredTime */ private void put(String key, V value, long expiredTime) { redisUtils.set(key, value, expiredTime); } /** * 注入对应的业务回调实例 * * @param callback 数据层逻辑回调实现,实现自RedisCacheDataCallBack<K, V>接口 */ public void setCallback(RedisCacheDataCallBack<K, V> callback) { if (callback == null) { throw new IllegalArgumentException( "the callback is null here , please check !"); } this.callback = callback; } /** * * @param key * @param value * @param expiredTime */ public int updateDbAndRedis(String key, V value, long expiredTime) { //存db int result = callback.updateDbFromRedis(value); redisUtils.delete(key); // FutureTask future = new FutureTask(() -> { // // //推缓存 // Log.info("redis异步更新数据库", "key:{} data:{}", key, value); // if (!redisUtils.hasKey(key)) { // try { // // Field idField; // PropertyDescriptor pd; // // if (value.getClass().getName().endsWith("WithBLOBs")) { // idField = value.getClass().getSuperclass().getDeclaredField("id"); // pd = new PropertyDescriptor(idField.getName(), value.getClass().getSuperclass()); // } else { // idField = value.getClass().getDeclaredField("id"); // pd = new PropertyDescriptor(idField.getName(), value.getClass()); // } // // Method getMethod = pd.getReadMethod(); // Long id = (Long) getMethod.invoke(value); // // if (id == null) { // return null; // } // V v = callback.getById(id); // put(key, v, expiredTime); // } catch (NoSuchFieldException e) { // log.error("id 不存在! 或者 调用 getById 失败", e); // } catch (IllegalAccessException e) { // log.error("redis异步更新数据库", e); // } catch (Exception e) { // log.error("redis异步更新数据库", e); // } // } // return null; // }); // executor.execute(future); return result; } /** * * @param key * @param value */ public int updateDbAndRedis(String key, V value) { return this.updateDbAndRedis(key,value,valueExpiredTime); } public int insertDbAndRedis(String cacheConsants,V value, long expiredTime){ int primaryKey = callback.insertDbFromRedis(value); // FutureTask<Void> future = new FutureTask(new Callable<Void>() { // public Void call() { // //推缓存 // Log.info("redis异步更新数据库","{key}:{data}",cacheConsants + primaryKey, value); // if (!redisUtils.hasKey(cacheConsants + primaryKey)) { // put(cacheConsants + primaryKey, value, expiredTime); // } // return null; // } // }); // executor.execute(future); return primaryKey; } public int insertDbAndRedis(String key,V value){ return this.insertDbAndRedis(key,value,valueExpiredTime); } public static void main(String[] args) { System.out.println("1"); FutureTask<Void> future = new FutureTask(new Callable<Void>() { public Void call() { //Thread.sleep(5); System.out.println("线程执行"); return null; } }); executor.execute(future); System.out.println("2"); } }
redis被动缓存
猜你喜欢
转载自572327713.iteye.com/blog/2415575
今日推荐
周排行