透过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缓存源码看大神编程思想

但是有一个问题,如果业务数据量非常大话,全部加载到内存中又会出现什么问题呢?

【感谢您的关注~】


分享到:


相關文章: