缓存架构Spring Boot缓存

从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,之后直接返回缓存。

未命名文件.png
上一篇下一篇

猜你喜欢

热点阅读