mybatis緩存的裝飾器模式

通常在開發生產中,對於新需求的實現,咱們通常會有兩種方式來處理,一種是直接修改已有組件的代碼,另外一種是使用繼承方式。第一種顯然會破壞已有組件的穩定性。第二種,會致使大量子類的出現。裝飾器模式能夠動態的爲對象添加功能,它是基於組合的方式來實現該功能的。組合優於繼承。java

裝飾器模式也是須要一個原始需求抽象類或者接口,由它的子類或者實現類來完成它的實際功能,這是正常需求。當咱們須要作擴展需求的時候,須要一個裝飾抽象類(注意這裏只有抽象類,沒有接口來繼承該原始需求抽象類或者接口,目的是爲了定義委託對象。再由該裝飾抽象類的子類來完成擴展的需求。具體實例能夠參考 設計模式整理 apache

在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爲例,實際上它有不少的裝飾器實現類)mybatis

//
// 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;
}
}
相關文章
相關標籤/搜索