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;