1、自动配置类;CacheAutoConfiguration
自动配置类是springboot的组件加载机制中的常见类,CacheAutoConfiguration类中关键定义了导入缓存相关的配置组件
@Import({
CacheAutoConfiguration.CacheConfigurationImportSelector.class, CacheAutoConfiguration.CacheManagerEntityManagerFactoryDependsOnPostProcessor.class})
CacheConfigurationImportSelector是CacheAutoConfiguration的内部类:
static class CacheConfigurationImportSelector implements ImportSelector {
CacheConfigurationImportSelector() {
}
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for(int i = 0; i < types.length; ++i) {
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}
它为我们导入了相关的缓存配置类如下:
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.GuavaCacheConfiguration
org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
2.xxxCacheConfiguration
因为容器中加载了如上的11中cache配置类,那么如何选择匹配的配置类呢?我们不妨看看其中一个配置类SimpleCacheConfiguration:
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnMissingBean({CacheManager.class})
@Conditional({CacheCondition.class})
class SimpleCacheConfiguration {
SimpleCacheConfiguration() {
}
debug会发现,容器会根据配置类中的@Conditional注解进行筛选判断,最终匹配到对应的"xxxCacheConfiguration",以SimpleCacheConfiguration为例,它会在容器中注册一个ConcurrentMapCacheManager(缓存管理器),代码如下:
@Bean
ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers) {
ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
List<String> cacheNames = cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
cacheManager.setCacheNames(cacheNames);
}
return (ConcurrentMapCacheManager)cacheManagerCustomizers.customize(cacheManager);
}
3.ConcurrentMapCacheManager 缓存管理器
这个类实现了CacheManager接口,可以获取和创建ConcurrentMapCache类型的缓存组件;
public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {
private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap(16);
@Nullable
public Cache getCache(String name) { //根据用户定义的缓存name获取对应的缓存
Cache cache = (Cache)this.cacheMap.get(name);
if (cache == null && this.dynamic) {
ConcurrentMap var3 = this.cacheMap;
synchronized(this.cacheMap) {
cache = (Cache)this.cacheMap.get(name);
if (cache == null) {
cache = this.createConcurrentMapCache(name); //找不到cache时则创建一个
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
protected Cache createConcurrentMapCache(String name) { //创建cache存放数据,返回的实际上是个ConcurrentMapCache
SerializationDelegate actualSerialization = this.isStoreByValue() ? this.serialization : null;
return new ConcurrentMapCache(name, new ConcurrentHashMap(256), this.isAllowNullValues(), actualSerialization);
}
}
所以ConcurrentMapCache的作用就是将数据保存在ConcurrentMap中;
public class ConcurrentMapCache extends AbstractValueAdaptingCache {
private final ConcurrentMap<Object, Object> store;
@Nullable
protected Object lookup(Object key) {
return this.store.get(key);
}
public void put(Object key, @Nullable Object value) {
this.store.put(key, this.toStoreValue(value));
}
}
它还提供了查找的相关功能如上的put()方法,是数据缓存数据获取和存放的核心。如此一来,就可将数据进行缓存。
4. 运行流程:
@Cacheable:
1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
(CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
public class SimpleKeyGenerator implements KeyGenerator {
public SimpleKeyGenerator() {
}
public Object generate(Object target, Method method, Object... params) {
return generateKey(params);
}
public static Object generateKey(Object... params) {
if (params.length == 0) {
return SimpleKey.EMPTY;
} else {
if (params.length == 1) {
Object param = params[0];
if (param != null && !param.getClass().isArray()) {
return param;
}
}
return new SimpleKey(params);
}
}
}
SimpleKeyGenerator生成key的默认策略;
如果没有参数;key=new SimpleKey();
如果有一个参数:key=参数的值
如果有多个参数:key=new SimpleKey(params);
3、没有查到缓存就调用目标方法;
4、将目标方法返回的结果,放进缓存中
@Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
核心:
1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator