通过Mybatis中的Cache接口认识责任链模式

852 阅读3分钟

这是我参与更文挑战的第8天,活动详情查看: 更文挑战

一、什么是责任链模式?

在结构上由多个部件,基于引用组成一串链条,行为上请求从链条的头部传递到各个节点,从而触发执行各个节点负责的业务逻辑。常见的springmvc中的拦截器和mybatis中的拦截器都应用到了责任链模式。在责任链模式中每个节点逻辑不通,分工明确,实现了代码解耦,可维护性较好。

二、Mybatis中的Cache接口是怎么做的?

先来看一下mybatis的cache接口的源码:

public interface Cache {
    String getId();

    //添加缓存
    void putObject(Object var1, Object var2);
    //获取缓存
    Object getObject(Object var1);

    Object removeObject(Object var1);

    void clear();

    int getSize();

    default ReadWriteLock getReadWriteLock() {
        return null;
    }
}

cache作为一个缓存接口,最主要的功能就是添加和获取缓存的功能,我们来看一下他是怎么添加缓存的呢? 可以看到putObject有11个实现。每个实现我们根据名字就能大概知道他们的职责。

image.png

public class SynchronizedCache implements Cache {
    private final Cache delegate;

    public synchronized void putObject(Object key, Object object) {
        this.delegate.putObject(key, object);
    }
}

看下SynchronizedCache这个实现类,他有一个Cache的全局变量,然后在putObject方法中直接调用传给了下一个接口实现。这个方法看着好像什么都没做,但是仔细看会发现方法上加上了synchronized关键字,所以这个实现其实是实现了一个线程安全的功能。

接着看下LoggingCache这个实现类,他同样的也是在方法中直接传给下一个实现去执行。这个实现类其实是为了在获取缓存的时候打印缓存的命中率的。

public class LoggingCache implements Cache {
    private final Log log;
    private final Cache delegate;
    protected int requests = 0;
    protected int hits = 0;

    public void putObject(Object key, Object object) {
        this.delegate.putObject(key, object);
    }
    //统计缓存命中率
    public Object getObject(Object key) {
        ++this.requests;
        Object value = this.delegate.getObject(key);
        if (value != null) {
            ++this.hits;
        }

        if (this.log.isDebugEnabled()) {
            this.log.debug("Cache Hit Ratio [" + this.getId() + "]: " + this.getHitRatio());
        }

        return value;
    }
}

然后还有LruCache,这个是缓存的一个淘汰策略,我们之前讲redis的时候就提过,内存是很宝贵的资源,不可能让数据无限膨胀,在达到阈值时都会有一个过期策略。这里这个实现类的功能就是在内存占用达到阈值时把最先保存的数据删除。

public class LruCache implements Cache {
    private final Cache delegate;
    private Map<Object, Object> keyMap;
    private Object eldestKey;

    public LruCache(Cache delegate) {
        this.delegate = delegate;
        this.setSize(1024);
    }

    public int getSize() {
        return this.delegate.getSize();
    }


    public void putObject(Object key, Object value) {
        this.delegate.putObject(key, value);
        this.cycleKeyList(key);
    }


    public Object removeObject(Object key) {
        return this.delegate.removeObject(key);
    }

    private void cycleKeyList(Object key) {
        this.keyMap.put(key, key);
        if (this.eldestKey != null) {
            this.delegate.removeObject(this.eldestKey);
            this.eldestKey = null;
        }

    }
}

最后看下PerpetualCache这个真正实现了我们缓存保存数据功能的实现类。

public class PerpetualCache implements Cache {
    private final String id;
    private Map<Object, Object> cache = new HashMap();

    public void putObject(Object key, Object value) {
        this.cache.put(key, value);
    }

通过源码我们可以很清晰地看到mybatis的cache最终也是保存到一个map上去的。

cache中还有其他很多实现类,这种方式的设计,将来这个缓存如果还需要添加什么其他功能,我们直接新增一个实现就可以了,这也是责任链模式最重要的功能。

以上,感谢阅读。