Spring缓存
缓存注解和概念
缓存SPEL
使用
在Springboot主配置类上打开注解Cache使用@EnableCaching,然后就可以在方法上使用上图中的各种缓存注解。
- @Cacheable
- cacheNames/values:指定缓存的名字,将方法的返回值放在哪个缓存中,可以使用数组
- key:缓存数据使用的key,可以使用SPEL表达式来,如果不指定,默认使用方法参数的值
- keyGenerator:key的生成器,指定key生成器的组件id,key/keyGenerator 二选一
- cacheManager:指定缓存管理器或者使用 cacheResolver:指定获取解析器
- condition:在指定条件下才缓存
- unless:当unless表达式为true时不缓存 eg:‘#result==null’
- sync:是否使用异步
- @CachePut既调用方法,也将方法结果更新至缓存
- @CachePut需要指定key与写入缓存时的@Cacheable key要一样(@CachePut可以使用#{result}而@Cacheable不行,因为@CachePut是运行在方法执行后的)
- @CacheEvict删除缓存数据
- allEntries 是否删除当前缓存组件下所有缓存 (默认false)
- beforeInvocation 缓存的删除是否在方法执行之前(默认false在方法之后)
- @Caching定义复杂的缓存规则
- @CacheConfig 类缓存配置 eg:配置整个类所有缓存名
原理
自动配置类 CacheAutoConfiguration
缓存的配置类
1
2
3
4
5
6
7
8
9
10
11
12Map<CacheType, Class<?>> mappings = new EnumMap<>(CacheType.class);
mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class);
mappings.put(CacheType.EHCACHE, EhCacheCacheConfiguration.class);
mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class);
mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class);
mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class);
mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class);
mappings.put(CacheType.REDIS, RedisCacheConfiguration.class);
mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class);
mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class);
mappings.put(CacheType.NONE, NoOpCacheConfiguration.class);
MAPPINGS = Collections.unmodifiableMap(mappings);默认生效SimpleCacheConfiguration给容器中注册了一个ConcurrentMapCacheManager可以创建和查找ConcurrentMapCache类型的缓存。而ConcurrentMapCache就是将数据放在了ConcurrentMap中。
运行流程
方法之前,先去查询cache ,根据cacheNames获取(CacheManager获取响应的缓存,第一次获取缓存会自动创建)
去缓存中查找缓存的内容 调用lookup,使用一个key从ConcurrentMap取值,默认key为方法参数的值。key是按照某种策略生成的,默认使用SimpleKeyGenerator生成key
1
2
3
4
5
6
7
8
9
10
11
12
13public 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);
}
如果没参数就使用SimpleKey.EMPTY,如果有1个就用第一个参数,如果多个就用SimpleKey包装后的对象
没有查到缓存,就调用目标方法,然后将目标方法返回的结果放进缓存中
总结:@Cacheable标记的方法,在执行之前会去检查缓存中是否有key对应的值,如果没有择运行方法,把返回值放入缓存中。
首先得到CacheManager得到Cache组件,key是使用keyGenerator生成的,默认使用SimpleKeyGenerator
Redis
Springboot默认使用SimpleCacheConfiguration最终将数据存放在ConcurrentMap中
使用
1 | <dependency> |
RedisAutoConfiguration会自动帮我在IOC注入stringRedisTemplate和RedisTemplate
stringRedisTemplate用来处理非KV数据
- String类型 stringRedisTemplate.opsForValue()
- list类型 stringRedisTemplate.opsForList()
- Set类型 stringRedisTemplate.opsForSet()
- hash散列 stringRedisTemplate.opsForHash()
- Zset有序集合 stringRedisTemplate.opsForZSet()
RedisTemplate用来处理KV数据
改变序列化的规则,选择用Jackson2JsonRedisSerializer转换为JSON格式,默认为JDK的序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyRedisConfig {
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setDefaultSerializer(new Jackson2JsonRedisSerializer(Employee.class));
return template;
}
}