内容概要
本篇博客是在Mybatis缓存机制(一)的基础上,自己手写Cache链,会去除Cache内容以外的代码,尽可能的还原MyBatis关于Cache的内容。
代码编写
Cache接口以及Cache实现类
- 新建一个Empty Module叫CacheImplement,新建package mybatis.cache
- 既然要实现Cache的相关功能,那么首先定义Cache的接口
package mybatis.cache;
/*
* @author:算法菜鸟飞高高
* @version:1.0
* @since:1.0
* */
public interface Cache {
// cache对象需要有自己的id,用getId返回它
String getId();
// 往缓存中添加数据
void putObject(Object key, Object value);
// 通过key取数据
Object getObject(Object key);
//通过key删除数据
void removeObject(Object key);
//清楚缓存中的所有数据
void clear();
//获取缓存中数据的个数
int getSize();
}
接口的方法与Mybatis中的几乎相同
- 实现基础Cache PerpetualCache,在mybatis.cache下新建class perpetualCache
package mybatis.cache;
import java.util.HashMap;
import java.util.Map;
public class PerpetualCache implements Cache{
private String id;
// 底层使用一个HashMap来存储缓存数据, get, put,size,remove,clear操作都是基于这个map
private Map<Object, Object> caches;
public PerpetualCache(String id) {
this.id = id;
caches = new HashMap<>();
}
@Override
public String getId() {
return id;
}
@Override
public void putObject(Object key, Object value) {
this.caches.put(key, value);
}
@Override
public Object getObject(Object key) {
return this.caches.get(key);
}
@Override
public void removeObject(Object key) {
this.caches.remove(key);
}
@Override
public void clear() {
this.caches.clear();
}
@Override
public int getSize() {
return this.caches.size();
}
}
- 实现SynchrolizedCache作为我们的decorator Cache,因为我们的关注点不在具体Cache实现的功能,而是责任链的应用,所以就先实现一个最简单的。
package mybatis.cache;
public class SynchrolizedCache implements Cache{
// 持有责任链的下一个Cache结点
private Cache delegate;
public SynchrolizedCache(Cache delegate) {
this.delegate = delegate;
}
@Override
public String getId() {
return delegate.getId();
}
// 对于所有修改以及访问map的方法都需要加synchronized修饰
@Override
public synchronized void putObject(Object key, Object value) {
delegate.putObject(key, value);
}
@Override
public synchronized Object getObject(Object key) {
return delegate.getObject(key);
}
@Override
public synchronized void removeObject(Object key) {
delegate.removeObject(key);
}
@Override
public synchronized void clear() {
delegate.clear();
}
@Override
public synchronized int getSize() {
return delegate.getSize();
}
}
CacheBuilder创建
目前我们实现了Cache接口,以及它的两个实现类,已经可以编写创建CacheBuilder类了。
public class CacheBuilder{
// 一个责任链对应一个id,这个后面Base Cache的构造器需要
private String id;
public CacheBuilder(String id){
this.id = id;
}
// 这个表示Base Cache,他与其它Cache的区别在于构造器上,它的构造器接受一个id,如PerpetualCache
//其它的Cache构造器接受另一个Cache对象,如SynchrolizedCache
private Class<? extends Cache>implement;
//用来保存责任链中所有的decorator Class
private ArrayList<Class<? extends Cache>> decorators = new ArrayList<>();
public CacheBuilder setImplement(Class<? extends Cache> implement){
this.implement = implement;
return this; // 返回this对象,使得用户可以链式调用方法
}
// 往责任链添加结点的方法
public CacheBuilder addDecorator(Class<? extends Cache> decorator){
if(decorator != null)
decorators.add(decorator);
return this;
}
// 利用Class对象生成Base Cache的方法
private Cache baseCacheInstance(String id){
// 声明一个Cache类的构造器
Constructor<? extends Cache> baseConstructor;
try {
//获得参数是String类型的构造器
baseConstructor = implement.getConstructor(String.class);
//利用构造器创建实例并返回
Cache cache = baseConstructor.newInstance(id);
return cache;
} catch (Exception e) {
throw new RuntimeException("cache " + implement.getName() + " build error " + e);
}
}
// 利用decorator的Class对象生成 Cache对象,与baseCacheInstance功能相同,区别是这个要求构造器
// 接受一个Cache类型的参数
private Cache decoratorInstance(Class<? extends Cache> decorator, Cache cache){
Constructor<? extends Cache> decoratorConstructor;
try {
decoratorConstructor = decorator.getConstructor(Cache.class);
Cache decoratorCache = decoratorConstructor.newInstance(cache);
return decoratorCache;
} catch (Exception e) {
throw new RuntimeException("decorator " + decorator.getName() + " build error " + e);
}
}
//构造责任链
public Cache build(){
// 保证Implement被赋值
setDefalutImplement();
//创建基础的Cache
Cache cache = baseCacheInstance(id);
//往责任链中添加Cache
for(Class<? extends Cache> decorator : decorators){
cache = decoratorInstance(decorator, cache);
}
return cache;
}
private void setDefalutImplement(){
if(implement == null)
setImplement(PerpetualCache.class);
}
}
测试CacheBuilder的效果
在package mybatis.pojo下创建Student类,作为缓存的数据。
package mybatis.pojo;
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在mybatis.test创建TestCacheBuilder类用来测试CacheBuilder
package mybatis.test;
import mybatis.cache.Cache;
import mybatis.cache.CacheBuilder;
import mybatis.cache.SynchrolizedCache;
import mybatis.pojo.Student;
public class TestCacheBuilder {
public static void main(String[] args) {
Cache cache = new CacheBuilder("test").addDecorator(SynchrolizedCache.class).build();
cache.putObject(1, new Student("zhangsan", 24));
System.out.println(cache.getObject(1));
}
}
分析CacheBuilder的设计优势
CacheBuilder几乎不依赖任何一个具体的Cache类,只有但用户没有指定implement时,才会使用PerpetualCache,利用反射的Constructor,可以实例化任何一个满足要求的decorator Cache。链式调用法则也方便了用户的使用。