说到Spring Boot缓存,那就不得不提JSR-107规范,它告诉我们在Java中如何规范地使用缓存。
JSR是Java Specification Requests的简称,通常译为”Java 规范提案“。具体而言,是指向JCP(Java Community Process,Java标准制定组织)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,通过一定的标准测试后,就可以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
JSR-107规范即JCache API,JCache规范定义了一种对Java对象临时在内存中进行缓存的方法,包括对象的创建、共享访问、假脱机(spooling)、失效、各JVM的一致性等,可被用于缓存JSP内最经常读取的数据,如产品目录和价格列表。利用JCache的缓存数据,可以加快大多数查询的反应时间(内部测试表明反应时间大约快15倍)。
在Spring Boot中使用缓存之前,我们有必要了解一下JCache。JCache定义了五个核心接口,分别是CachingProvider,CacheManager,Cache,Entry和Expiry。
一个CachingProvider可以创建和管理多个CacheManager,并且一个CacheManager只能被一个CachingProvider所拥有,而一个应用可以在运行期间访问多个CachingProvider。
一个CacheManager可以创建和管理多个唯一命名的Cache,且一个Cache只能被一个CacheManager所拥有,这些Cache存在于CacheManager的上下文中。
Cache是一个类似Map的数据结构
Entry是一个存储在Cache中的key-value对
Expiry是指存储在Cache中的Entry的有效期,一旦超过这个时间,Entry将处于过期状态,即不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

image
Spring 3.1开始,引入了Spring Cache,即Spring 缓存抽象。通过定义org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术,并支持使用JCache注解简化开发过程。
Cache接口为缓存的组件规范定义,包含缓存的各种操作集合。Spring中为Cache接口提供了各种xxxCache的实现:RedisCache,EhCacheCache,ConcurrentMapCache等。
我们通过部分源码详细了解一下Cache接口和CacheManager接口。
Cache接口
- public interface Cache {
- //Cache名称
- String getName();
-
- //Cache负责缓存的对象
- Object getNativeCache();
-
- /**
- * 获取key对应的ValueWrapper
- * 没有对应的key,则返回null
- * key对应的value是null,则返回null对应的ValueWrapper
- */
- @Nullable
- Cache.ValueWrapper get(Object key);
-
- //返回key对应type类型的value
- @Nullable
-
T get(Object key, @Nullable Class type); -
- //返回key对应的value,没有则缓存Callable::call,并返回
- @Nullable
-
T get(Object key, Callable valueLoader); -
- //缓存目标key-value(替换旧值),不保证实时性
- void put(Object key, @Nullable Object value);
-
- //插入缓存,并返回该key对应的value;先调用get,不存在则用put实现
- @Nullable
- default Cache.ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
- Cache.ValueWrapper existingValue = this.get(key);
- if (existingValue == null) {
- this.put(key, value);
- }
-
- return existingValue;
- }
-
- //删除缓存,不保证实时性
- void evict(Object key);
-
- //立即删除缓存:返回false表示剔除前不存在制定key活不确定是否存在;返回true,表示该key之前存在
- default boolean evictIfPresent(Object key) {
- this.evict(key);
- return false;
- }
-
- //清除所有缓存,不保证实时性
- void clear();
-
- //立即清楚所有缓存,返回false表示清除前没有缓存或不能确定是否有;返回true表示清除前有缓存
- default boolean invalidate() {
- this.clear();
- return false;
- }
-
- public static class ValueRetrievalException extends RuntimeException {
- @Nullable
- private final Object key;
-
- public ValueRetrievalException(@Nullable Object key, Callable> loader, Throwable ex) {
- super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex);
- this.key = key;
- }
-
- @Nullable
- public Object getKey() {
- return this.key;
- }
- }
-
- //缓存值的一个包装器接口,实现类为SimpleValueWrapper
- @FunctionalInterface
- public interface ValueWrapper {
- @Nullable
- Object get();
- }
- }
可以看出,Cache接口抽象了缓存的 get put evict 等相关操作。
AbstractValueAdaptingCache
- public abstract class AbstractValueAdaptingCache implements Cache {
-
- //是否允许Null值
- private final boolean allowNullValues;
-
- protected AbstractValueAdaptingCache(boolean allowNullValues) {
- this.allowNullValues = allowNullValues;
- }
-
- public final boolean isAllowNullValues() {
- return this.allowNullValues;
- }
-
- @Nullable
- public ValueWrapper get(Object key) {
- return this.toValueWrapper(this.lookup(key));
- }
-
- @Nullable
- public
T get(Object key, @Nullable Class type ) { - //查询到的缓存值做fromStoreValue转换
- Object value = this.fromStoreValue(this.lookup(key));
- //转换后非null值且无法转换为type类型则抛出异常
- if (value != null && type != null && !type.isInstance(value)) {
- throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value);
- } else {
- return value;
- }
- }
-
- //从缓存中获取key对应的value,子类实现
- @Nullable
- protected abstract Object lookup(Object key);
-
- //对于从缓存中获取的值,允许为空且值为NullValue时,处理为null
- @Nullable
- protected Object fromStoreValue(@Nullable Object storeValue) {
- return this.allowNullValues && storeValue == NullValue.INSTANCE ? null : storeValue;
- }
-
- //对于要插入缓存的null值,在允许null值的情况下处理为NullValue;否则抛出异常IllegalArgumentException
- protected Object toStoreValue(@Nullable Object userValue) {
- if (userValue == null) {
- if (this.allowNullValues) {
- return NullValue.INSTANCE;
- } else {
- throw new IllegalArgumentException("Cache '" + this.getName() + "' is configured to not allow null values but null was provided");
- }
- } else {
- return userValue;
- }
- }
-
- //get操作依据,查询到缓存值非null,则fromStoreValue转换后包装成SimpleValueWrapper返回
- @Nullable
- protected ValueWrapper toValueWrapper(@Nullable Object storeValue) {
- return storeValue != null ? new SimpleValueWrapper(this.fromStoreValue(storeValue)) : null;
- }
- }
抽象类AbstractValueAdaptingCache实现了Cache接口,主要抽象了对NULL值的处理逻辑。
allowNullValues属性表示是否允许处理NULL值的缓存
fromStoreValue方法处理NULL值的get操作,在属性allowNullValues为true的情况下,将NullValue处理为NULL
toStoreValue方法处理NULL值得put操作,在属性allowNullValues为true的情况下,将NULL处理为NullValue,否则抛出异常
toValueWrapper方法提供Cache接口中get方法的默认实现,从缓存中读取值,再通过fromStoreValue转化,最后包装为SimpleValueWrapper返回
ValueWrapper get(Object key)和T get(Object key, @Nullable Classtype)方法基于上述方法实现
ValueWrapper get(Object key)和@Nullable Classtype)方法基于上述方法实现
lookup抽象方法用于给子类获取真正的缓存值
ConcurrentMapCache
- public class ConcurrentMapCache extends AbstractValueAdaptingCache {
- private final String name;
- //定义ConcurrentMap缓存
- private final ConcurrentMap
- //如果要缓存的是值对象的copy,则由此序列化代理类处理
- @Nullable
- private final SerializationDelegate serialization;
-
- public ConcurrentMapCache(String name) {
- this(name, new ConcurrentHashMap(256), true);
- }
-
- //默认允许处理null
- public ConcurrentMapCache(String name, boolean allowNullValues) {
- this(name, new ConcurrentHashMap(256), allowNullValues);
- }
-
- //默认serialization = null
- public ConcurrentMapCache(String name, ConcurrentMap
- this(name, store, allowNullValues, (SerializationDelegate)null);
- }
-
- protected ConcurrentMapCache(String name, ConcurrentMap
- super(allowNullValues);
- Assert.notNull(name, "Name must not be null");
- Assert.notNull(store, "Store must not be null");
- this.name = name;
- this.store = store;
- this.serialization = serialization;
- }
-
- //serialization不为空,缓存值对象的copy
- public final boolean isStoreByValue() {
- return this.serialization != null;
- }
-
- public final String getName() {
- return this.name;
- }
-
- public final ConcurrentMap
- return this.store;
- }
-
- //实现lookup:store#get
- @Nullable
- protected Object lookup(Object key) {
- return this.store.get(key);
- }
-
- //基于ConcurrentMap::computeIfAbsent方法实现;get和put的值由fromStoreValue和toStoreValue处理Null
- @Nullable
- public
T get(Object key, Callable valueLoader) { - return this.fromStoreValue(this.store.computeIfAbsent(key, (k) -> {
- try {
- return this.toStoreValue(valueLoader.call());
- } catch (Throwable var5) {
- throw new ValueRetrievalException(key, valueLoader, var5);
- }
- }));
- }
-
- public void put(Object key, @Nullable Object value) {
- this.store.put(key, this.toStoreValue(value));
- }
-
- @Nullable
- public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
- Object existing = this.store.putIfAbsent(key, this.toStoreValue(value));
- return this.toValueWrapper(existing);
- }
-
- public void evict(Object key) {
- this.store.remove(key);
- }
-
- public boolean evictIfPresent(Object key) {
- return this.store.remove(key) != null;
- }
-
- public void clear() {
- this.store.clear();
- }
-
- public boolean invalidate() {
- boolean notEmpty = !this.store.isEmpty();
- this.store.clear();
- return notEmpty;
- }
-
- protected Object toStoreValue(@Nullable Object userValue) {
- Object storeValue = super.toStoreValue(userValue);
- if (this.serialization != null) {
- try {
- return this.serialization.serializeToByteArray(storeValue);
- } catch (Throwable var4) {
- throw new IllegalArgumentException("Failed to serialize cache value '" + userValue + "'. Does it implement Serializable?", var4);
- }
- } else {
- return storeValue;
- }
- }
-
- protected Object fromStoreValue(@Nullable Object storeValue) {
- if (storeValue != null && this.serialization != null) {
- try {
- return super.fromStoreValue(this.serialization.deserializeFromByteArray((byte[])((byte[])storeValue)));
- } catch (Throwable var3) {
- throw new IllegalArgumentException("Failed to deserialize cache value '" + storeValue + "'", var3);
- }
- } else {
- return super.fromStoreValue(storeValue);
- }
- }
- }
ConcurrentMapCache继承了抽象类AbstractValueAdaptingCache,是Spring的默认缓存实现。它支持对缓存对象copy的缓存,由SerializationDelegate serialization 处理序列化,默认为 null 即基于引用的缓存。缓存相关操作基于基类 AbstractValueAdaptingCache 的 null 值处理,默认允许为 null。
CacheManager
- public interface CacheManager {
- @Nullable
- //获取指定name的Cache,可能延迟创建
- Cache getCache(String name);
-
- //获取当前CacheManager下的Cache name集合
- Collection
getCacheNames() ; - }
CacheManager 基于 name 管理一组 Cache。当然,CacheManager也有很多实现类,如ConcurrentMapCacheManager、AbstractCacheManager及SimpleCacheManager,这些xxxCacheManager类都是为了制定Cache的管理规则,这里就不再深入探讨了。
除了第二章中提到的Cache接口和CacheManager接口,在使用Spring 缓存抽象时,我们还会用到一些JCache注解。