从Spring缓存源码看大神编程思想
2019-03-02 本文已影响56人
我的小熊不见了
从Spring缓存源码看大神编程思想
随着用户的增长我们,数据库承受的压力越来越大,此时我们就需要使用Spring
中的缓存,减少用户的操作直击数据库带来的风险。在使用Spring
缓存的时候我们通常会使用org.springframework.cache
包下的一些注解,但是这篇文章并不是介绍这几个注解的使用方式,而是通过解读该包下的源代码,透过代码看看Spring
作者的编程思想。
AbstractCacheManager
这个类在org.springframework.cache.support
包下。
initializeCaches
这是这个类的初始化缓存的方法:
public void initializeCaches() {
//实际存储缓存的map
private final ConcurrentMap<String, Cache> 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);
}
}
从上面的方法中可以看到,初始化时先从loadCaches()
方法加载以前的缓存,经过处理将缓存的key放进set
中,将从redis
取出的缓存载入内存中。
来看看初始化方法中调用的方法:
loadCaches
@Override
protected Collection<RedisCache> loadCaches() {
List<RedisCache> caches = new LinkedList<>();
for (Map.Entry<String, RedisCacheConfiguration> entry : initialCacheConfiguration.entrySet()) {
caches.add(createRedisCache(entry.getKey(), entry.getValue()));
}
return caches;
}
createRedisCache
protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
return new RedisCache(name, cacheWriter, cacheConfig != null ? cacheConfig : defaultCacheConfig);
}
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,之后直接返回缓存。