java实现简单的本地缓存

/**
 * @author : hilite
 * @version : 1.0
 * @Title : LocalCache
 * @Description :
 * @date : 2019/9/18
 * @CopyRight : Copyright (c) 2015-2019 All Rights Reserved.
 * @Compony : hilite.cn Inc.
 */
public class LocalCache {

   private static final Logger logger = LoggerFactory.getLogger(LocalCache.class);
   //默认缓存容量
   private static final int DEFAULT_CAPACITY = 500;
   //最大缓存容量
   private static final int MAX_CAPACITY = 1000000;
   //监控清除过期缓存频率
   private static final int MONITOR_FREQUENCY = 3;

   //构建本地缓存的map
   private static ConcurrentHashMap<String, CacheEntity> cache = new ConcurrentHashMap<String, CacheEntity>(DEFAULT_CAPACITY);

   //监控线程启动
   static{
      new Thread(new MonitorThread()).start();
   }

   //监控线程
    static class MonitorThread implements Runnable{
      @Override
      public void run() {
         while(true){
            try {
               logger.info("START CACHE MONITOR");
               TimeUnit.SECONDS.sleep(MONITOR_FREQUENCY);
               checkTime();
            }catch (Exception e){
               logger.error("MONITOR CACHE HAS THROWS AN EXCEPTION:", e);
            }
         }
      }

      //过期key剔除
      private void checkTime(){
         cache.entrySet().stream().forEach(item -> {
            CacheEntity value = item.getValue();
            if(value.getExpireTime() != -1 && TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - value.getGmtCreate()) > value.getExpireTime()){
               String key = item.getKey();
               cache.remove(key);
               logger.info("REMOVE EXPIRE KEY:{}", key);
            }
         });

      }
   }

   /**
    * 将key-value 保存到本地缓存并设置缓存过期时间
    * @param key
    * @param value
    * @param expireTime 过期时间,如果是-1 则表示永不过期
    * @return
    */
   public boolean put(String key, Object value, int expireTime){
      if(cache.size() >= MAX_CAPACITY){
         throw new RuntimeException("CAPACITY OVERFLOW!");
      }
      return putCloneValue(key, value, expireTime);
   }

   /**
    *将值通过序列化 clone 处理后保存到缓存中,可以解决值引用的问题
    *@param key
    *@param value
    *@param expireTime 过期时间,如果是-1 则表示永不过期
    *@return boolean
    */
   private boolean putCloneValue(String key, Object value, int expireTime){
      try {
         CacheEntity cacheEntity = clone(new CacheEntity(value, System.nanoTime(), expireTime));
         /*CacheEntity cacheEntity = (CacheEntity)javassist();
         cacheEntity.setObj(value);
         cacheEntity.setExpireTime(expireTime);
         cacheEntity.setGmtCreate(System.nanoTime());*/
         cache.put(key, cacheEntity);
         return true;
      }catch (Exception e){
         logger.error("PUT VALUE HAS THROWS AN EXCEPTION:", e);
         return false;
      }
   }

   /**
    * javassist测试
    */
   public <T extends Serializable> T javassist() throws Exception {
      ClassPool classPool = ClassPool.getDefault();
      CtClass ctClass = classPool.makeClass("com.zaxxer.hikari.cacheLocal.CacheEntity1");
      CtField ctField1 = new CtField(classPool.get("java.lang.Object"), "value", ctClass);
      CtField ctField2 = new CtField(CtClass.longType, "gmtCreate", ctClass);
      CtField ctField3 = new CtField(CtClass.intType, "expireTime", ctClass);
      CtField ctField4 = new CtField(CtClass.intType, "serialVersionUID", ctClass);
      ctField1.setModifiers(Modifier.PRIVATE);
      ctField2.setModifiers(Modifier.PRIVATE);
      ctField3.setModifiers(Modifier.PRIVATE);
      ctField4.setModifiers(Modifier.PRIVATE);
      ctField4.setModifiers(Modifier.STATIC);
      ctField4.setModifiers(Modifier.FINAL);
      ctClass.addField(ctField4, "7172649826282703560L");
      ctClass.setInterfaces(new CtClass[]{classPool.get("java.io.Serializable")});
      ctClass.addMethod(CtNewMethod.setter("setValue", ctField1));
      ctClass.addMethod(CtNewMethod.setter("setGmtCreate", ctField2));
      ctClass.addMethod(CtNewMethod.setter("setExpireTime", ctField3));
      ctClass.addMethod(CtNewMethod.getter("getValue", ctField1));
      ctClass.addMethod(CtNewMethod.getter("getGmtCreate", ctField2));
      ctClass.addMethod(CtNewMethod.getter("getExpireTime", ctField3));
      CtConstructor constructor = new CtConstructor(new CtClass[]{classPool.get("java.lang.Object"), classPool.get("long"), classPool.get("int")}, ctClass);
      constructor.setBody("{$0.value = $1;$0.gmtCreate = $2;$0.expireTime = $3;}");
      ctClass.addConstructor(constructor);
      ctClass.writeFile("/dd/aa");
      Object o = ctClass.toClass().newInstance();
      ctClass.detach();
      return (T) o;
   }

   /**
    * 序列化 克隆处理
    * @param obj
    * @return CacheEntity
    */
   private <T extends Serializable> T clone(T obj){
      T target = null;
//      try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos);
//           ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))){
//         oos.writeObject(obj);
//         target = (CacheEntity) ois.readObject();
//      }catch (Exception e){
//         logger.error("CLONE VALUE HAS THROWS AN EXCEPTION:", e);
//      }
//      return target;
      try {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         ObjectOutputStream oos = new ObjectOutputStream(baos);
         oos.writeObject(obj);
         oos.close();
         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
         ObjectInputStream ois = new ObjectInputStream(bais);
         target = (T) ois.readObject();
         ois.close();
      }catch (Exception e){
         logger.error("CLONE VALUE HAS THROWS AN EXCEPTION:", e);
      }
      return target;
   }

   /**
   *  清除缓存
   */
   public void clear(){
      cache.clear();
   }

   /**
    * 根据key得到value
    * @param key
    * @return Object
    */
   public Object getValue(String key){
      return cache.get(key).getObj();
   }
}

 

/**
 * @author : hilite
 * @version : 1.0
 * @Title : CacheEntity
 * @Description :
 * @date : 2019/9/18
 * @CopyRight : Copyright (c) 2015-2019 All Rights Reserved.
 * @Compony : hilite.cn Inc.
 */
public class CacheEntity implements Serializable {

   private static final long serialVersionUID = 7172649826282703560L;

   private Object obj;

   private long gmtCreate;

   private int expireTime;

   public CacheEntity(Object obj, long gmtCreate, int expireTime) {
      this.obj = obj;
      this.gmtCreate = gmtCreate;
      this.expireTime = expireTime;
   }

   public Object getObj() {
      return obj;
   }

   public void setObj(Object obj) {
      this.obj = obj;
   }

   public long getGmtCreate() {
      return gmtCreate;
   }

   public void setGmtCreate(long gmtCreate) {
      this.gmtCreate = gmtCreate;
   }

   public int getExpireTime() {
      return expireTime;
   }

   public void setExpireTime(int expireTime) {
      this.expireTime = expireTime;
   }
}

   参考了网上的资料,自己写了个实现本地缓存的类,clone方法只是一个保险的方法,防止出现值传递的问题,会出现这个问题的原因是因为在外部存储对象(不包括String及包装类型)做缓存时,如果再存储过后,对对象进行修改的话,也会对缓存中的对象进行修改,关于java值传递的问题可自行百度,这里不做赘述。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值