JSR-107简介
为了统一缓存开发规范,以及提升缓存开发的扩展性,J2EE发布了JSR-107缓存开发规范。
Java Caching定义了5个核心接口,分别是CachingProvider、CacheManger、Cache、Entry和Expiry
- CachingProvider:定义了创建、配置、获取、管理和控制多个CacheManger。一个应用可以再运行期间访问多个CachingProvider
- CacheManger:定义了创建、配置、获取、管理和控制多个唯一命名Cache,这些Cache存在于CacheManger的上下文中
- Cache:是一个类似Map的数据结构并临时存储以Key为索引的值
- Entry:key-value键值对
- Expiry:每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期状态。过期状态的条目不可访问、更新和删除。可通过该ExpiryPolicy设置
大概可以用这样的数据结构表示:
Map<CachingProviderName,Map<CacheMangerName,Map<CacheName,Map<k,v>>
Spring缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManger接口来统一不同的缓存技术;并支持使用Cache(JSR-107)注解简化开发
- Cache接口为换出的组件规范定义,包含缓存的各种操作集合
- Cache接口下Spring提供了个xxxCache的实现;如RedisCache、EhCacheCache、ConcurrentMapCache等;
缓存注解
缓存SpEL表达式
缓存工作原理
- 自动配置类:CacheAutoConfiguration 他的作用主要是通过Import注解引入各个缓存配置类
- 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
- 然后按顺序根据配置类上的Conditional条件判断,是哪个配置类生效,默认生效为SimpleCacheConfiguration配置类
- SimpleCacheConfiguration只做了一件事,那就是向容器中注入了一个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获取和创建ConcurrentMapCache缓存组件。使用ConcurrentMap进行管理缓存组件,可以看出实现的数据结构其实就是ConcurrentHashMap
public class ConcurrentMapCacheManager {
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
/**
* 通过name获取缓存组件,如果没有就创建一个
*/
@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;
}
/**
* 创建一个ConcurrentMapCache缓存组件
*/
protected Cache createConcurrentMapCache(String name) {
SerializationDelegate actualSerialization = (isStoreByValue() ? this.serialization : null);
return new ConcurrentMapCache(name, new ConcurrentHashMap<>(256),
isAllowNullValues(), actualSerialization);
}
}
- ConcurrentMapCache将数据保存在ConcurrentMap中,也是使用ConcurrentHashMap进行缓存数据的操作
public class ConcurrentMapCache extends AbstractValueAdaptingCache {
// 组件的名称
private final String name;
// 数据存放在这里
private final ConcurrentMap<Object, Object> store;
// 使用ConcurrentHashMap进行数据操作
public ConcurrentMapCache(String name) {
this(name, new ConcurrentHashMap<>(256), true);
}
/**
* 查询缓存
*/
@Override
@Nullable
protected Object lookup(Object key) {
return this.store.get(key);
}
@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);
}
}));
}
// 存放缓存数据,实际就是map.put(key,value)
@Override
public void put(Object key, @Nullable Object value) {
this.store.put(key, toStoreValue(value));
}
}
运行流程
@Cacheable:
- 方法运行前,按照cacheNames查询缓存组件,第一次获取如果没有会自动创建缓存组件;
- 去Cache中查找缓存的内容,使用一个key,默认为方法的参数;key是通过keyGenerator生成的,SimpleCacheConfiguration默认使用SimpleKeyGenerator生成
public class SimpleKeyGenerator implements KeyGenerator {
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);
}
}
- 没有查询到缓存就调用目标方法
- 将目标方法返回的结果,放进缓存中
public class ConcurrentMapCache extends AbstractValueAdaptingCache {
@Override
public void put(Object key, @Nullable Object value) {
this.store.put(key, toStoreValue(value));
}
}
Gitee源码