mybatis缓存的装饰器模式

原创
2019/03/20 23:54
阅读数 434

一般在开发生产中,对于新需求的实现,我们一般会有两种方式来处理,一种是直接修改已有组件的代码,另一种是使用继承方式。第一种显然会破坏已有组件的稳定性。第二种,会导致大量子类的出现。装饰器模式可以动态的为对象添加功能,它是基于组合的方式来实现该功能的。组合优于继承。

装饰器模式也是需要一个原始需求抽象类或者接口,由它的子类或者实现类来完成它的实际功能,这是正常需求。当我们需要做扩展需求的时候,需要一个装饰抽象类(注意这里只有抽象类,没有接口来继承该原始需求抽象类或者接口,目的是为了定义委托对象。再由该装饰抽象类的子类来完成扩展的需求。具体实例可以参考 设计模式整理

在mybatis的缓存模块中,它使用了装饰器模式的变体,将装饰抽象类直接放到了装饰实现类的内部,为了做一个比较,我们来看一下它的原始需求接口,基本实现类和它的装饰实现类

package org.apache.ibatis.cache;

import java.util.concurrent.locks.ReadWriteLock;
//原始需求接口
public interface Cache {
    //该缓存对象的id
    String getId();
    //向缓存中添加数据,一般情况下,key是CacheKey,value是查询结果
    void putObject(Object var1, Object var2);
    //根据指定的key,在缓存中查找对应的结果对象
    Object getObject(Object var1);
    //删除key对应的缓存项
    Object removeObject(Object var1);
    //清空缓存
    void clear();
    //缓存项的个数
    int getSize();
    //获取读写锁
    ReadWriteLock getReadWriteLock();
}

基本实现类PerpetualCache,我们可以看到它就是对一个HashMap的操作,实现了缓存的基本功能。

package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

public class PerpetualCache implements Cache {
    //Cache对象的唯一标识
    private final String id;
    //用以记录缓存项的Map对象
    private Map<Object, Object> cache = new HashMap();

    public PerpetualCache(String id) {
        this.id = id;
    }

    public String getId() {
        return this.id;
    }

    public int getSize() {
        return this.cache.size();
    }

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

    public Object getObject(Object key) {
        return this.cache.get(key);
    }

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

    public void clear() {
        this.cache.clear();
    }

    public ReadWriteLock getReadWriteLock() {
        return null;
    }

    public boolean equals(Object o) {
        if(this.getId() == null) {
            throw new CacheException("Cache instances require an ID.");
        } else if(this == o) {
            return true;
        } else if(!(o instanceof Cache)) {
            return false;
        } else {
            Cache otherCache = (Cache)o;
            return this.getId().equals(otherCache.getId());
        }
    }

    public int hashCode() {
        if(this.getId() == null) {
            throw new CacheException("Cache instances require an ID.");
        } else {
            return this.getId().hashCode();
        }
    }
}

它的装饰器实现类(以BlockingCache为例,实际上它有很多的装饰器实现类)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.apache.ibatis.cache.decorators;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;
//阻塞版本的缓存装饰器
public class BlockingCache implements Cache {
    //阻塞超时时长
    private long timeout;
    //所有的装饰器实现类所共有的底层缓存,所代表着装饰抽象类,虽然这里不是一个抽象类,而是一个接口
    //相当于在装饰抽象类中使用委托机制是一个道理,这里委托的也是基本缓存实现类PerpetualCache
    private final Cache delegate;
    //每个key都有所对应的重入锁ReetrantLock对象
    private final ConcurrentHashMap<Object, ReentrantLock> locks;

    public BlockingCache(Cache delegate) {
        this.delegate = delegate;
        this.locks = new ConcurrentHashMap();
    }
    
    public String getId() {
        return this.delegate.getId();
    }

    public int getSize() {
        return this.delegate.getSize();
    }
    //此处进行了重入锁的释放,对委托类进行调用外,进行了增强
    public void putObject(Object key, Object value) {
        try {
            this.delegate.putObject(key, value);
        } finally {
            this.releaseLock(key);
        }

    }
    //此处进行了锁操作和释放,具体可以看到后面的实现
    public Object getObject(Object key) {
        this.acquireLock(key);
        Object value = this.delegate.getObject(key);
        if(value != null) {
            this.releaseLock(key);
        }

        return value;
    }

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

    public void clear() {
        this.delegate.clear();
    }

    public ReadWriteLock getReadWriteLock() {
        return null;
    }
    //由key来得到锁
    private ReentrantLock getLockForKey(Object key) {
        //重入锁对象
        ReentrantLock lock = new ReentrantLock();
        //如果locks(ConcurrentHashMap)中存在key,则赶回value,如果不存在则将key,value写入locks中,并返回null
        ReentrantLock previous = (ReentrantLock)this.locks.putIfAbsent(key, lock);
        //如果key拿不到锁,则使用新的lock,如果能拿到则使用拿到的value
        return previous == null?lock:previous;
    }
    //获得锁
    private void acquireLock(Object key) {
        //拿到重入锁
        Lock lock = this.getLockForKey(key);
        //如果该锁是带超时时间的
        if(this.timeout > 0L) {
            try {
                //在timeout时长后去拿取锁(注意这里不是锁多长时间),拿到返回true,拿不到返回false
                boolean acquired = lock.tryLock(this.timeout, TimeUnit.MILLISECONDS);
                //拿不到锁,抛出异常
                if(!acquired) {
                    throw new CacheException("Couldn't get a lock in " + this.timeout + " for the key " + key + " at the cache " + this.delegate.getId());
                }
            } catch (InterruptedException var4) {
                throw new CacheException("Got interrupted while trying to acquire lock for key " + key, var4);
            }
        //如果该锁不带超时时间
        } else {
            //直接锁定
            lock.lock();
        }

    }
    //释放锁
    private void releaseLock(Object key) {
        //拿取锁
        ReentrantLock lock = (ReentrantLock)this.locks.get(key);
        //判断拿到的锁是否是当前线程持有的
        if(lock.isHeldByCurrentThread()) {
            //释放锁
            lock.unlock();
        }

    }

    public long getTimeout() {
        return this.timeout;
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
}
展开阅读全文
加载中

作者的其它热门文章

打赏
0
1 收藏
分享
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部