透過Spring Boot中cacheAble緩存源碼看大神編程思想

透過Spring Boot中cacheAble緩存源碼看大神編程思想

隨著應用用戶的增長,數據庫承受的壓力越來越大,此時我們就需要使用Spring中的緩存,減少用戶的操作直擊數據庫帶來的風險。在使用Spring緩存的時候我們通常會使用org.springframework.cache包下的一些註解,但是這篇文章並不是介紹這幾個註解的使用方式,而是通過解讀該包下的源代碼,透過代碼看看Spring作者的編程思想。

AbstractCacheManager

這個類在org.springframework.cache.support包下。

initializeCaches

這是這個類的初始化緩存的方法:

public void initializeCaches() {
//實際存儲緩存的map
private final ConcurrentMap<string> cacheMap = new ConcurrentHashMap<>(16);
//緩存中key的集合
private volatile Set<string> cacheNames = Collections.emptySet();

// 加載緩存
Collection extends Cache> caches = loadCaches();
// 加鎖,初始化的時候防止其他線程的干擾
synchronized (this.cacheMap) {
// 初始化
this.cacheNames = Collections.emptySet();
// 清空
this.cacheMap.clear();
Set<string> cacheNames = new LinkedHashSet<>(caches.size());
// 循環從redis中取出的緩存數據放進內存
for (Cache cache : caches) {
String name = cache.getName();
this.cacheMap.put(name, decorateCache(cache));
cacheNames.add(name);
}
this.cacheNames = Collections.unmodifiableSet(cacheNames);
}
}
/<string>/<string>/<string>

從上面的方法中可以看到,初始化時先從loadCaches()方法加載以前的緩存,經過處理將緩存的key放進set中,將從redis取出的緩存載入內存中。

來看看初始化方法中調用的方法:

loadCaches

@Override
protected Collection<rediscache> loadCaches() {

List<rediscache> caches = new LinkedList<>();

for (Map.Entry<string> entry : initialCacheConfiguration.entrySet()) {
caches.add(createRedisCache(entry.getKey(), entry.getValue()));
}

return caches;
}
/<string>/<rediscache>/<rediscache>

loadCaches是從redis中取出緩存。

decorateCache

修飾緩存:


@Override
protected Cache decorateCache(Cache cache) {
return (isTransactionAware() ? new TransactionAwareCacheDecorator(cache) : cache);
}

源碼中該方法和事務有關,如果有事務的話會使用事務相關的類包裝一層返回,沒有的話直接返回。

Collections.unmodifiableSet

該方法返回指定set的不可修改視圖。

getCache

再來看獲取緩存的的方法:

@Override
@Nullable
public Cache getCache(String name) {
// 先從map中通過key直接取值
Cache cache = this.cacheMap.get(name);
if (cache != null) {
return cache;
}
else {
// Fully synchronize now for missing cache creation...
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = getMissingCache(name);
if (cache != null) {
cache = decorateCache(cache);
this.cacheMap.put(name, cache);
updateCacheNames(name);
}
}
return cache;
}
}
}

get方法先直接從map中取緩存,如果沒取到的話,鎖住map再取一次。以防在這個過程中緩存已經被其他的線程刷到map中了。如果還是沒取到,會從getMissingCache()方法取一次,代碼如下。

getMissingCache

@Override
protected RedisCache getMissingCache(String name) {

return allowInFlightCacheCreation ? createRedisCache(name, defaultCacheConfig) : null;
}

getMissingCache方法從redis中取緩存,如果取到了的話,將緩存修飾一下,放進map裡以便下次直接從map中取並且更新存放緩存key的set,之後直接返回緩存。

透過Spring Boot中cacheAble緩存源碼看大神編程思想

但是有一個問題,如果業務數據量非常大話,全部加載到內存中又會出現什麼問題呢?

【感謝您的關注~】


分享到:


相關文章: