【Spring Cache】一 Cache CacheManager
前言
本系列主要想了解下 Spring Cache
的实现原理,结合部分源码及其细节,旨在使用 Spring Cache
时可以更加得心应手
先从 Cache
CacheManager
了解起来
Cache
public interface Cache {
// 缓存名称
String getName();
// 缓存真正负责缓存的对象
Object getNativeCache();
/**
* 获取 key 对应的 ValueWrapper
* 没有对应的 key 就返回 null
* key 对应的 v 是 null 的话返回的是 null 对应的 ValueWrapper
*/
@Nullable
ValueWrapper get(Object key);
/**
* 返回 key 对应 type 类型的 v
*/
@Nullable
<T> T get(Object key, @Nullable Class<T> type);
/**
* 如果有 key 对应的 v 就返回
* 如果没有就缓存 Callable::call 并返回
*/
@Nullable
<T> T get(Object key, Callable<T> valueLoader);
/**
* 缓存目标 kv(替换旧值),不保证实时性
*/
void put(Object key, @Nullable Object value);
/**
* 立即插入缓存,默认基于先 get 不存在则 put 操作实现
*/
@Nullable
default ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
ValueWrapper existingValue = get(key);
if (existingValue == null) {
put(key, value);
}
return existingValue;
}
/**
* 剔除缓存,不保证实时性
*/
void evict(Object key);
/**
* 立即剔除缓存
* 返回 false 表示剔除前不存在指定 key 或不确定是否存在
* 返回 true 表示该 key 之前存在
*/
default boolean evictIfPresent(Object key) {
evict(key);
return false;
}
// 清除所有缓存,不保证实时性
void clear();
/**
* 立即清除所有缓存
* 返回 false 表示清除前没有缓存或不能确定是否有
* 返回 true 表示清除前有缓存
*/
default boolean invalidate() {
clear();
return false;
}
/**
* 缓存值的一个包装器接口
* 实现类 SimapleValueWrapper
*/
@FunctionalInterface
interface ValueWrapper {
@Nullable
Object get();
}
// ...ValueRetrievalException
}
缓存的顶级接口,抽象了缓存的 get
put
evict
相关操作
NoOpCache
一个未作任何实际缓存操作的实现,应该主要是用来兼容不适应缓存的场景,细节略
AbstractValueAdaptingCache
public abstract class AbstractValueAdaptingCache implements Cache {
// 是否允许 null 值
private final boolean allowNullValues;
protected AbstractValueAdaptingCache(boolean allowNullValues) {
this.allowNullValues = allowNullValues;
}
// ...
@Override
@Nullable
public ValueWrapper get(Object key) {
// get 操作依赖 toValueWrapper
return toValueWrapper(lookup(key));
}
@Override
@SuppressWarnings("unchecked")
@Nullable
public <T> T get(Object key, @Nullable Class<T> type) {
// 查询到的缓存值 fromStoreValue 转换
Object value = fromStoreValue(lookup(key));
// 转换后非 null 值无法类型转换则抛出异常
if (value != null && type != null && !type.isInstance(value)) {
throw new IllegalStateException(
"Cached value is not of required type [" + type.getName() + "]: " + value);
}
return (T) value;
}
// 从缓存中获取 key 对应的 v,子类实现
@Nullable
protected abstract Object lookup(Object key);
/**
* 对于从缓存中获取的值,允许为空且值为 NullValue 时,处理为 null
*/
@Nullable
protected Object fromStoreValue(@Nullable Object storeValue) {
if (this.allowNullValues && storeValue == NullValue.INSTANCE) {
return null;
}
return storeValue;
}
/**
* 对于要插入缓存的 null 值,在允许 null 值的情况下处理为 NullValue
* 否则抛出异常 IllegalArgumentException
*/
protected Object toStoreValue(@Nullable Object userValue) {
if (userValue == null) {
if (this.allowNullValues) {
return NullValue.INSTANCE;
}
throw new IllegalArgumentException(
"Cache '" + getName() + "' is configured to not allow null values but null was provided");
}
return userValue;
}
/**
* get 操作基于此完成
* 查询到缓存值非 null 则 fromStoreValue 转换后包装成 SimpleValueWrapper 返回
*/
@Nullable
protected Cache.ValueWrapper toValueWrapper(@Nullable Object storeValue) {
return (storeValue != null ? new SimpleValueWrapper(fromStoreValue(storeValue)) : null);
}
}
核心的抽象基类实现,主要抽象了对 NULL
值的处理逻辑:
boolean allowNullValues
:属性allowNullValues
定义是否允许处理NULL
值缓存fromStoreValue
方法主要处理NULL
值的get
操作相关,在允许NULL
值缓存的情况下,处理NullValue
为null
toStoreValue
方法主要处理NULL
值的put
操作相关,在允许NULL
值缓存的情况下,处理null
为NullValue
,否则抛异常toValueWrapper
方法主要提供get
的默认实现,将缓存中读取缓存后fromStoreValue
转换后包装成SimpleValueWrapper
返回ValueWrapper get(Object key)
和T get(Object key, @Nullable Class<T> type)
方法基于上述方法实现- 提供抽象方法
lookup
交给子类来获取真正的缓存值
ConcurrentMapCache
public class ConcurrentMapCache extends AbstractValueAdaptingCache {
private final String name;
// 基于 ConcurrentMap 缓存
private final ConcurrentMap<Object, Object> store;
// 如果要缓存的是值对象的 copy,则由此序列化代理类处理
@Nullable
private final SerializationDelegate serialization;
// ...
// 默认允许处理 null
public ConcurrentMapCache(String name) {
this(name, new ConcurrentHashMap<>(256), true);
}
// 默认 serialization = null
public ConcurrentMapCache(String name, ConcurrentMap<Object, Object> store, boolean allowNullValues) {
this(name, store, allowNullValues, null);
}
// serialization 不为空是缓存值对象的 copy
public final boolean isStoreByValue() {
return (this.serialization != null);
}
// ...
// 实现 lookup:store#get
@Override
@Nullable
protected Object lookup(Object key) {
return this.store.get(key);
}
/**
* 基于 ConcurrentMap::computeIfAbsent 方法实现
* get 和 put 的值由 fromStoreValue 和 toStoreValue 处理 NULL
*/
@SuppressWarnings("unchecked")
@Override
@Nullable
public <T> T get(Object key, Callable<T> valueLoader) {
return (T) fromStoreValue(this.store.computeIfAbsent(key, k -> {
try {
return toStoreValue(valueLoader.call());
}
catch (Throwable ex) {
throw new ValueRetrievalException(key, valueLoader, ex);
}
}));
}
// ...
}
Spring
内置的基于 ConcurrentMap
的缓存实现
- 支持对缓存值对象
copy
的缓存,由SerializationDelegate serialization
处理序列化,默认为null
即基于引用的缓存 - 缓存相关操作基于基类
AbstractValueAdaptingCache
的null
值处理,默认允许为null
demo
public class ConcurrentMapCacheDemo {
@Test
public void test() {
ConcurrentMapCache cache = new ConcurrentMapCache("test");
cache.put("1", "a");
cache.get("2", () -> null);
System.out.println(cache.get("1").get());
System.out.println(cache.get("2").get());
cache.clear();
System.out.println(cache.get("1"));
System.out.println(cache.get("2"));
}
}
写个 demo
加深印象
CacheManager
public interface CacheManager {
@Nullable
// 获取指定 name 的 Cache,可能延迟创建
Cache getCache(String name);
// 获取当前 CacheManager 下的 cache name 集合
Collection<String> getCacheNames();
}
CacheManager
基于 name
管理一组 Cache
NoOpCacheManager
基于 name
维护一组 NoOpCache
,细节略
ConcurrentMapCacheManager
public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
// 是否动态创建缺省 Cache
private boolean dynamic = true;
// 是否允许空值
private boolean allowNullValues = true;
// 是否缓存值对象的副本
private boolean storeByValue = false;
// 序列化辅助类
@Nullable
private SerializationDelegate serialization;
public ConcurrentMapCacheManager() {
}
/**
* 如果指定一个非 null 的 cacheNames
* 这里就会基于此创建对应的 静态缓存,即不会再创建新的缺省缓存了
*/
public ConcurrentMapCacheManager(String... cacheNames) {
setCacheNames(Arrays.asList(cacheNames));
}
// 基于传入的 cacheNames 创建静态缓存,之后就不允许创建缺省缓存了
public void setCacheNames(@Nullable Collection<String> cacheNames) {
if (cacheNames != null) {
for (String name : cacheNames) {
this.cacheMap.put(name, createConcurrentMapCache(name));
}
this.dynamic = false;
}
else {
this.dynamic = true;
}
}
// ...
@Override
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(this.cacheMap.keySet());
}
@Override
@Nullable
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
/**
* 如果允许创建缺省缓存,则基于 createConcurrentMapCache 创建
*/
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;
}
// 基于配置属性创建对应的 ConcurrentMapCache
protected Cache createConcurrentMapCache(String name) {
SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256), isAllowNullValues(), actualSerialization);
}
}
根据类名可以看出,它是用来管理一组 ConcurrentMapCache
的 CacheManager
- 它提供了一个有意思的属性
boolean dynamic
,意味着是否允许创建缺省缓存,即目标name
的缓存不存在时创建对应的ConcurrentMapCache
- 提供了构造方法
ConcurrentMapCacheManager(String... cacheNames)
,意味着基于传入的cacheNames
构造一组静态缓存,此后就不能在创建缺省缓存了 getCache
方法允许在获取不到指定缓存的情况下,根据属性boolean dynamic
决定是否创建缺省缓存- 创建缺省缓存方法
createConcurrentMapCache
:基于配置属性创建对应的ConcurrentMapCache
demo
public class ConcurrentMapCacheManagerDemo {
@Test
public void test() {
ConcurrentMapCacheManager cacheManager
= new ConcurrentMapCacheManager("test1", "test2");
cacheManager.getCache("test1")
.get("1", () -> "a");
// 指定了 cacheNames,无法创建缺省缓存,NPE
cacheManager.getCache("test3")
.get("1", () -> "b");
}
}
示例中指定了 cacheNames
,因此无法创建缺省缓存
CompositeCacheManager
Spring
常用的 设计模式 —— 组合模式
,其下可以管理一组 CacheManager
,其 getCache
方法返回查到的第一个 Cache
,细节略
AbstractCacheManager
public abstract class AbstractCacheManager implements CacheManager, InitializingBean {
// 基于 ConcurrentMap 管理缓存
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
// 基于 Set 管理 cache name
private volatile Set<String> cacheNames = Collections.emptySet();
// 是个 InitializingBean,生命周期后期调用 afterPropertiesSet 方法
@Override
public void afterPropertiesSet() {
initializeCaches();
}
public void initializeCaches() {
// 加载所有 Cache,由子类实现
Collection<? extends Cache> caches = loadCaches();
/**
* 基于上述 Cache 维护
* cacheMap:name -> cache
* cacheNames
*/
synchronized (this.cacheMap) {
this.cacheNames = Collections.emptySet();
this.cacheMap.clear();
Set<String> cacheNames = new LinkedHashSet<>(caches.size());
for (Cache cache : caches) {
String name = cache.getName();
this.cacheMap.put(name, decorateCache(cache));
cacheNames.add(name);
}
this.cacheNames = Collections.unmodifiableSet(cacheNames);
}
}
// 加载缓存由子类实现
protected abstract Collection<? extends Cache> loadCaches();
@Override
@Nullable
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache != null) {
return cache;
}
/**
* 如果没找到对应的 cache,这个地方允许基于 getMissingCache
* 构造一个对应的缺省 cache
*/
Cache missingCache = getMissingCache(name);
if (missingCache != null) {
// double check 同步检查
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = decorateCache(missingCache);
this.cacheMap.put(name, cache);
updateCacheNames(name);
}
}
}
return cache;
}
// 构造缺省 Cache
@Nullable
protected Cache getMissingCache(String name) {
return null;
}
// ...
}
AbstractCacheManager
,通用的实现基类,它可以维护一组不同的 Cache
- 它是一个
InitializingBean
,在afterPropertiesSet
阶段加载所有的Cache
(子类实现),基于此维护对应的cacheMap
和cacheNames
loadCaches
方法由子类实现,加载对应的Cache
sgetCache
方法在获取不到对应的Cache
时,允许基于getMissingCache
方法创建缺省Cache
(默认null
)
SimpleCacheManager
public class SimpleCacheManager extends AbstractCacheManager {
private Collection<? extends Cache> caches = Collections.emptySet();
public void setCaches(Collection<? extends Cache> caches) {
this.caches = caches;
}
@Override
protected Collection<? extends Cache> loadCaches() {
return this.caches;
}
}
AbstractCacheManager
的默认实现,loadCaches
方法返回指定的 Cache
集合
demo
public class ExtendSimpleCacheManagerDemo {
// 拓展 SimpleCacheManager 提供了缺省缓存实现:new ConcurrentMapCache(name)
public static class ExtendSimpleCacheManager extends SimpleCacheManager {
@Override
protected Cache getMissingCache(String name) {
return new ConcurrentMapCache(name);
}
}
@Configuration
public static class Config {
@Bean
public CacheManager cacheManager() {
ExtendSimpleCacheManager cacheManager
= new ExtendSimpleCacheManager();
// 创建一个默认缓存
ConcurrentMapCache cache = new ConcurrentMapCache("test");
cache.put("1", "a");
List<Cache> caches = new ArrayList<Cache>() {{
add(cache);
// ...
}};
cacheManager.setCaches(caches);
return cacheManager;
}
}
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext
= new AnnotationConfigApplicationContext(Config.class);
CacheManager bean = applicationContext.getBean(CacheManager.class);
// 第一个缓存是被 loadCaches 的
System.out.println(bean.getCache("test")
.get("1").get());
// 创建了缺省缓存
bean.getCache("test2")
.put("1", "b");
bean.getCacheNames()
.forEach(System.out::println);
}
}
- 该示例中拓展了
SimpleCacheManager
的getMissingCache
方法来提供一个缺省Cache
- 容器中注册该实例,并提供一个默认缓存
test
- 测试代码读取
test
的缓存值并创建缺省缓存test2
总结
源码结合示例,了解了 Spring Cache
定义的两个基类接口
Cache
,抽象缓存相关的操作CacheManager
,管理一组Cache
s