在日常開發中,我們會用到進程內緩存(Map)和分佈式緩存(Redis),緩存能夠很大程度降低數據庫的壓力.但是在日常開發中,每個人都寫自己的緩存,沒有統一的標準.導致整個項目內部全是單個成員自定義的緩存.所以需要在程序內部定義一套緩存模板規範化使用緩存.
緩存模板開發思路:
- 緩存我們常用的操作就和數據庫操作一樣,包括 增刪改查,所以這裏定義緩存的api參考數據庫的acid操作,但是緩存操作需要加鎖,不然會讀到髒數據.所以這裏我們使用讀寫鎖來做一致性操作處理.
- 緩存管理器,在整個服務中緩存管理器是一個唯一的.就像Redis的StringTemplate一樣.所以緩存管理器需要寫成雙重加鎖單例類.
- 緩存主鍵,自定義緩存主鍵常量,緩存的唯一性標識
代碼實現
- Cache類,緩存模板
/**
* @author caishen
* @version 1.0
* @className Cache
* @date 2019/10/26 1:58
* 自分で書いたコードの各行を擔當する
* 緩存模板
**/
public abstract class Cache<K,V> {
final Map<K, V> m = new HashMap<>();
final ReadWriteLock rwl = new ReentrantReadWriteLock();
final Lock r = rwl.readLock();
final Lock w = rwl.writeLock();
/**
* get key
* @param key
* @return
*/
public V get(K key) {
r.lock();
try {
return m.get(key);
} finally {
r.unlock();
}
}
/**
* 獲取當前緩存下面所有的key
* @return
*/
public Set<K> keys(){
return m.keySet();
}
/**
* 返回當前緩存下面的entrySet
* @return
*/
public Set<Map.Entry<K,V>> getEntrySet(){
r.lock();
try{
return m.entrySet();
} finally {
r.unlock();
}
}
/**
* put key
* @param key
* @param value
* @return
*/
public V put(K key, V value) {
w.lock();
try {
return m.put(key, value);
} finally {
w.unlock();
}
}
/**
* remove key
* @param key
* @return
*/
public V remove(K key) {
w.lock();
try {
return m.remove(key);
} finally {
w.unlock();
}
}
/**
* 模板方法,調用子類實現的init方法
*/
void _init() {
w.lock();
try {
init();
} finally {
w.unlock();
}
}
/**
* 緩存初始化,子類實現
*/
protected abstract void init();
}
- CacheManager 緩存管理器
/**
* @author caishen
* @version 1.0
* @className CacheManager
* @date 2019/10/26 2:00
* 自分で書いたコードの各行を擔當する
* 緩存管理類
**/
public class CacheManager<K,V> {
private final Map<String,Cache<K,V>> cacheMap = new ConcurrentHashMap<>();
private CacheManager(){}
public static volatile CacheManager cacheManager;
/**
* 單例模式 雙重加鎖
* @return
*/
public static CacheManager getInstance() {
if (null == cacheManager) {
synchronized (CacheManager.class) {
if (null == cacheManager) {
cacheManager = new CacheManager();
}
}
}
return cacheManager;
}
/**
* 判斷該key的緩存是否存在
* @param cacheKey
* @return
*/
public Boolean containsCacheKey(String cacheKey){
return cacheMap.containsKey(cacheKey);
}
/**
* 註冊緩存
* @param cacheKey 緩存key
* @param cache
*/
public void registerCache(String cacheKey, Cache<K, V> cache) {
cache._init();
cacheMap.put(cacheKey, cache);
}
/**
* 從指定緩存中獲取數據
* @param cacheKey 緩存Key
* @param key
* @return
*/
public V getValue(String cacheKey, K key) {
Cache<K, V> cache = cacheMap.get(cacheKey);
if(!Assert.isNull(cache)) {
return cache.get(key);
}
return null;
}
/**
* 獲取指定的緩存
* @param cacheKey
* @return
*/
public Cache<K,V> getCache(String cacheKey){
return cacheMap.get(cacheKey);
}
/**
* 設置緩存
* @param cacheKey 緩存Key
* @param key
* @param value
*/
public void put(String cacheKey, K key, V value) {
Cache<K, V> cache = cacheMap.get(cacheKey);
if(!Assert.isNull(cache)){
cache.put(key, value);
}
}
/**
* 設置緩存 並返回修改值
* @param cacheKey 緩存Key
* @param key
* @param value
*/
public V putAndSet(String cacheKey, K key, V value) {
Cache<K, V> cache = cacheMap.get(cacheKey);
if(!Assert.isNull(cache)) {
cache.put(key, value);
}
return value;
}
/**
* 從指定緩存中刪除數據
* @param cacheKey 緩存Key
* @param key
*/
public V remove(String cacheKey, K key) {
Cache<K, V> cache = cacheMap.get(cacheKey);
if(!Assert.isNull(cache)) {
return cache.remove(key);
}
return null;
}
}
- 調用示例
/**
* @author caishen
* @version 1.0
* @className TestCache
* @date 2019/12/19 11:53
* 自分で書いたコードの各行を擔當する
**/
public class TestCache extends Cache {
@Override
protected void init() {
//do something
}
// 直接調用這個方法就註冊了
public void register() {
CacheManager.getInstance().registerCache("TEST_CACHE_KEY", this);
}
}