SpringBoot学习-part49缓存工作原理&Cachable运行流程

Cache的自动配置

启动后根据加载的依赖,导入相应Cache配置模块
在这里插入图片描述缓存的配置类:
在这里插入图片描述

org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration
org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration

控制台输出
在这里插入图片描述
启动过程中SimpleCacheConfiguration 会注入一个cacheManager的@Bean方法,提供的是一个同步的缓存管理器(ConcurrentMapCacheManager)。

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {

	@Bean
	ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
			CacheManagerCustomizers cacheManagerCustomizers) {
		ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
		List<String> cacheNames = cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			cacheManager.setCacheNames(cacheNames);
		}
		return cacheManagerCustomizers.customize(cacheManager);
	}

}

其中ConcurrentMapCacheManager包含

private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);

可以按照名字String获取Cache,如果get不到将会创建。

	@Override
	@Nullable
	public Cache getCache(String name) {
		Cache cache = this.cacheMap.get(name);
		if (cache == null && this.dynamic) {
			synchronized (this.cacheMap) {
				cache = this.cacheMap.get(name);
				if (cache == null) {
					cache = createConcurrentMapCache(name);
					this.cacheMap.put(name, cache);
				}
			}
		}
		return cache;
	}

ConcurrentCacheManager内部创建Cache的方法:

	protected Cache createConcurrentMapCache(String name) {
		SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
		return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256), isAllowNullValues(), actualSerialization);
	}

而在ConcurrentMapCache内部我们可以发现,cache用来盛放Entry的实际容器是ConcurrentMap。

在这里插入图片描述
而所有Cache的实现类的统一接口是:Cache。

在这里插入图片描述

运行案例

测试案例:
http://localhost:8080/emp/2
如果不指定cache中entry的key生成方式或策略,默认参数名作为key,Cache<Key,Entry<K,V>>

    @Cacheable(cacheNames={"emp"})
    public Employee getEmpById(Integer id){
        System.out.println("查询 " + id + " 号员工");
        return  employeeMapper.getEmpById(id);
    }

@Cachable:
查找id为2的员工

1.从CacheManager获取相应的缓存,这里的缓存名字为emp。
2.首次调用Cachable方法,必然为null,所以将会创建该缓存。

在这里插入图片描述

3.创建出来的缓存将会被放在ConcurrentMap<String, Cache>类型的 cacheMap中。
4.拿到对应的缓存后,继续从Cache的实现来ConcurrentMapCache中查找key为2的Entry。

	@Override
	@Nullable
	protected Object lookup(Object key) {
		return this.store.get(key);
	}

首次get特定缓存内容

if (cacheHit != null && !hasCachePut(contexts)) {
	// If there are no put requests, just use the cache hit
	cacheValue = cacheHit.get();
	returnValue = wrapCacheValue(method, cacheValue);
}
else {
	// Invoke the method if we don't have a cache hit
	returnValue = invokeOperation(invoker);
	cacheValue = unwrapReturnValue(returnValue);
}

每次调用标注了Cachable的方法,
会先从CacheManager中获得cache,
在尝试从缓存中查找目标key的值。
查找的依据依次是:cache的名字,cache中相应的entry的名字。
其中相应entry的名字,根据key的生成策略获得。

查找前先要获得相应entry的名字(key)

这个key将作为在cache中进行查找的依据
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述默认使用SimpleKeyGenerator,也可以自行指定生成策略。

  • 如果有且仅有一个参数,则使用该参数作为key
  • 如果没有参数,则key = new SimpleKey()
  • 如果有多个参数,key= new SimpleKey(params)
public static Object generateKey(Object... params) {
		if (params.length == 0) {
			return SimpleKey.EMPTY;
		}
		if (params.length == 1) {
			Object param = params[0];
			if (param != null && !param.getClass().isArray()) {
				return param;
			}
		}
		return new SimpleKey(params);
	}

如果缓存没有命中,则执行sql语句。

调试结果:
在这里插入图片描述执行sql语句过后,根据unless、condition等条件,判断查询获得结果是否应该存入缓存。

	protected void doPut(Cache cache, Object key, @Nullable Object result) {
		try {
			cache.put(key, result);
		}
		catch (RuntimeException ex) {
			getErrorHandler().handleCachePutError(ex, cache, key, result);
		}
	}
	@Override
	public void put(Object key, @Nullable Object value) {
		this.store.put(key, toStoreValue(value));
	}
	private final ConcurrentMap<Object, Object> store;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值