简单仿写Mybatis中的Cache

仿写Mybatis中的Cache

在mybatis中提供了很多Cache,每一个Cache都有不同的特性

简单仿写Mybatis中的Cache_第1张图片

 

其中,我们使用了装饰者模式来仿写Cache

首先定义规范接口

public interface Cache {
	public void putObject(Object key,Object value);
    public Object getObject(Object key);
    public Object removeObject(Object key);
    public void clear();
    public int size();
}

普通的缓存对象,内部使用的是HashMap作为数据存储,没有提供缓存淘汰机制,容易引发

内存溢出现象,以及线程不安全问题。

/**
 * 负责真正存储数据的一个对象
 * 将数据存储到map中
 */
public class PerpetualCache implements Cache {
	/**
	 * 内部真正的cache对象
	 */
	private Map cache=null;
	@Override
	public void putObject(Object key, Object value) {
		cache=new HashMap<>();
		cache.put(key,value);
	}


	@Override
	public Object getObject(Object key) {
		if(cache==null) {
			return null;
		}
		return cache.get(key);
	}


	@Override
	public Object removeObject(Object key) {
		if(cache==null) {
			return null;
		}
		return cache.remove(key);
	}


	@Override
	public void clear() {
		cache.clear();
	}


	@Override
	public int size() {
		return cache.size();
	}
	
@Override
	public String toString() {
		return cache.toString();
	}


public static void main(String[] args) {
	 Cache cache=new PerpetualCache();
     cache.putObject("A", 100);
     cache.putObject("B", 200);
     cache.putObject("C", 300);
     System.out.println(cache);
     cache.removeObject("D");
     cache.clear();
     System.out.println(cache.size());
}
}

线程安全的缓存对象,使用的是同步关键字实现

package com.cy.java.Cache;
/**
 * 线程安全的cache对象
 * synchronized 实现
 */
public class SynchronizedCache implements Cache{
	private Cache cache;
	 public SynchronizedCache(Cache cache) {
         this.cache=cache;
 }
	@Override
	public synchronized void putObject(Object key, Object value) {
		cache.putObject(key, value);
	}


	@Override
	public synchronized Object getObject(Object key) {
		return cache.getObject(key);
	}

	@Override
	public synchronized Object removeObject(Object key) {
		return cache.removeObject(key);
	}

	@Override
	public synchronized void clear() {
		cache.clear();
	}

	@Override
	public synchronized int size() {
		return cache.size();
	}
	 @Override
     public String toString() {
             return cache.toString();
     }
	public static void main(String[] args) {
      SynchronizedCache cache=
        new SynchronizedCache(new PerpetualCache());
        cache.putObject("A", 100);
        cache.putObject("B", 200);
        cache.putObject("C", 300);
        System.out.println(cache);
}
}

先进先出缓存,实现FIFO的缓存淘汰机制

package com.cy.java.cache;

/**
 * 基于FIFO(先进先出)算法,定义FifoCache,当缓存满的时候,从缓存中移除头部数据
 *  @author Jason_liu
 *  2020年5月14日,上午9:12:13
 */
public class FifoCache implements Cache {
	private Cache cache;
    /**最大容量*/
	private int maxCap;
	/**通过此队列记录元素的添加顺序*/
	private Deque keyOrders;
	
	public FifoCache(Cache cache,int maxCap) {
		this.cache=cache;
		this.maxCap=maxCap;
		this.keyOrders=new LinkedList<>();
	}
	/**向cache中放数据:cache满了要淘汰最早放入的元素*/
	@Override
	public void putObject(Object key, Object value) {
		//记录key的添加顺序
		this.keyOrders.addLast(key);
		//检查容器是否已满,满了则移除头部元素
		if(keyOrders.size()>maxCap) {
             //先移除队列中保存的key值,基于key值移除缓存中数据
			Object eldestKey=keyOrders.removeFirst();
			cache.removeObject(eldestKey);
		}
		//添加新元素
		cache.putObject(key, value);
	}
	@Override
	public Object getObject(Object key) {
		
		return cache.getObject(key);
	}
	@Override
	public Object removeObject(Object key) {
		Object object=cache.removeObject(key);
		keyOrders.remove(key);
		return object;
	}
	@Override
	public void clear() {
		cache.clear();
		keyOrders.clear();
	}
	@Override
	public int size() {
		return cache.size();
	}
	@Override
	public String toString() {
		
		return cache.toString();
	}
	public static void main(String[] args) {
		Cache cache=new FifoCache(new PerpetualCache(), 3);
		cache.putObject("A", 100);
		cache.putObject("B", 200);
		cache.putObject("C", 300);
		cache.putObject("D", 400);
		System.out.println(cache);//BCD
		cache.getObject("B");
		cache.putObject("E",500);
		System.out.println(cache);//CDE
	}
} 
  
 

基于LRU算法实现的Cache

/**
 * LRU缓存的简单实现
 * @author Jason_liu
 * 2020年5月14日,上午9:34:50
 */
public class LruCache implements Cache {
	private Cache cache;
    /**保存不常用的Key值*/
	private Object eldestKey;
    /**主要使用此对象实现LRU机制*/
	private Map keyMap;
	public LruCache(Cache cache,int maxCap) {
		this.cache=cache;
		this.keyMap=new LinkedHashMap(){
            /*每次调用put方法都会自动调用此方法*/
			protected boolean removeEldestEntry(
					Map.Entry eldest) {
			   	/*如果cache的长度大于最大的容量
			   	 * 则开始获取最不常用的cache的key
			   	 * 保存在eldestKey这个属性上面
				 */
				boolean isFull=size()>maxCap;
				if(isFull) {
					eldestKey=eldest.getKey();
				}
				return isFull;
			}
		};
	}
	@Override
	public void putObject(Object key, Object value) {
		cache.putObject(key, value);
		keyMap.put(key, value);
		if(eldestKey!=null) {
			cache.removeObject(eldestKey);
			eldestKey=null;
		}
	}
	@Override
	public Object getObject(Object key) {
		keyMap.get(key);
		return cache.getObject(key);
	}
	@Override
	public Object removeObject(Object key) {
		return cache.removeObject(key);
	}
	@Override
	public void clear() {
		cache.clear();
		keyMap.clear();
	}
	@Override
	public int size() {
		return cache.size();
	}
	@Override
	public String toString() {
		return cache.toString();
	}
public static void main(String[] args) {
	SynchronizedCache cache=
            new SynchronizedCache( new LruCache(new PerpetualCache(),3));
	cache.putObject("A", 100);
	cache.putObject("B", 100);
	cache.putObject("C", 100);
	cache.putObject("D", 100);
	System.out.println(cache.getObject("A"));
	System.out.println(cache);
  }
}

软引用Cache,内存不足数据自动被清除

/**
 * 软引用cache
 * @author Jason_liu
 * 2020年5月14日,下午1:57:22
 */
public class SoftCache implements Cache {
	private Cache cache;
	/**基于此队列记录被垃圾回收的对象:当软引用引用的对象被GC时
	 * 会将被GC的对象的软引用存储到ReferenceQueue中*/
	private ReferenceQueue garbageQueue;
	public SoftCache(Cache cache) {
		this.cache=cache;
		this.garbageQueue=new ReferenceQueue();
	}
	/**
	 * 构建软引用类型
	 */
	private static class SoftEntry extends SoftReference{
		private Object key;
		public SoftEntry(Object key,Object referent,
				ReferenceQueue rQueue) {
			super(referent, rQueue);
			this.key=key;
		}
	}
	/**从队列中取出已经被gc对象,然后从cache中移除*/
	private  void removeGarbageObjects() {
		SoftEntry softEntry=null;
		while((softEntry=(SoftEntry)garbageQueue.poll())!=null) {
			cache.removeObject(softEntry.key);
		}
	}
	@Override
	public void putObject(Object key, Object value) {
		//移除队列中记录的对象
		removeGarbageObjects();
		//对象进行软引用关联
		cache.putObject(key, new SoftEntry(key, value,
				garbageQueue));
	}
	/**
	 * 基于key获取cache中的SoftReference引用的对象
	 */
	@Override
	public Object getObject(Object key) {
		//1.从cache获取引用对象并校验
		SoftEntry softEntry=(SoftEntry)cache.getObject(key);
		if(softEntry==null)cache.removeObject(key);
		//2.基于引用获取引用的对象并校验
		Object target=softEntry.get();
		if(target==null)cache.removeObject(key);
		return target;
	}
	@Override
	public Object removeObject(Object key) {
		//1.移除垃圾对象
		removeGarbageObjects();
		//2.移除目标引用对象
		Object target=cache.removeObject(key);
		return target;
	}
	@Override
	public void clear() {
		removeGarbageObjects();
		cache.clear();
	}
	@Override
	public int size() {
		removeGarbageObjects();
		return cache.size();
	}
	@Override
	public String toString() {
		return cache.toString();
	}
	/**
	 * 测试:在内存不足和内存充足的情况下cache中的数据变化
	 * @param args
	 */
	//-Xmx5m -Xms5m -XX:+PrintGCDetails
	public static void main(String[] args) {
		Cache cache=new SoftCache(new PerpetualCache());
		cache.putObject("A", new byte[1024*1024]);
		cache.putObject("B", new byte[1024*1024]);
		cache.putObject("C", new byte[1024*1024]);
		cache.putObject("D", new byte[1024*1024]);
		cache.putObject("E", new byte[1024*1024]);
		cache.putObject("F", new byte[1024*1024]);
		cache.putObject("K", new byte[1024*1024]);
		System.out.println(cache.size());
		System.out.println(cache);
	}
} 
  

序列化Cache

/**
 * 序列化cache
 * 1)对象存储到cache之前先进行序列化,让后进行存储,存储cache的对象是一个字节数组的引用。
 * 2)从cache获取对象需要将字节数组反序列化。
 * @author Jason_liu
 * 2020年5月14日,下午2:00:24
 */
public class SerializedCache implements Cache {
	private Cache cache;
	public SerializedCache(Cache cache) {
		this.cache=cache;
	}
	/**对象序列化*/
	private byte[] serialize(Object value) {
		//1.构建流对象
		ByteArrayOutputStream bos=null;
		ObjectOutputStream out=null;
		bos=new ByteArrayOutputStream();//内置一个可扩容的数组
		try {
		out=new ObjectOutputStream(bos);//装饰模式
		//2.对象序列化
		out.writeObject(value);//obj对象需要实现Serializable
		out.flush();
		return bos.toByteArray();
		}catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("序列化失败");
		}finally {
		//3.释放资源
		 try{if(out!=null) {out.close();out=null;}}catch(Exception e) {}
		}
	}
	/**对象的反序列化*/
	private Object deserialize(byte[] array){
	    //1.创建流对象
		ByteArrayInputStream bis=null;
		ObjectInputStream ois=null;
		bis=new ByteArrayInputStream(array);
		try {
		ois=new ObjectInputStream(bis);
		//2.对象的反序列化
		Object obj=ois.readObject();
		return obj;
		}catch(Exception e) {
		e.printStackTrace();
		throw new RuntimeException("反序列化失败");
		}finally {
		//3.释放资源
		try{if(bis!=null) {bis.close();bis=null;}}catch(Exception e) {}
		}
	}
	@Override
	public void putObject(Object key, Object value) {
		//1.将对象序列化
		byte[] array=serialize(value);
		//2.将序列化后的字节数组引用存储到cache
		cache.putObject(key,array);
	}
	@Override
	public Object getObject(Object key) {
		//1.基于key获取缓存中的字节数组引用
		byte[] array=(byte[])cache.getObject(key);
		//2.将字节数组反序列化为对象
		return deserialize(array);
	}
	@Override
	public Object removeObject(Object key) {
		return deserialize((byte[])cache.removeObject(key));
	}
	@Override
	public void clear() {
		cache.clear();
	}
	@Override
	public int size() {
		return cache.size();
	}
	public static void main(String[] args) {
		Cache cache=new SerializedCache(new PerpetualCache());
		cache.putObject("A", 500);
		Object a1=cache.getObject("A");
		Object a2=cache.getObject("A");
		System.out.println(a1==a2);//false
	}


}

 

你可能感兴趣的:(mybatis,数据库相关,java,缓存,队列,mybatis3.3.0)