Spring Cache
前言
对于一些后端系统,如果不是电商系统,在前文中的redis集成
之后,一般会采用使用redis
封装工具类
进行存储一些数据,但是在springBoot
前 spring
已经集成了缓存中间件,一般来说普通的缓存可以使用缓存中间件进行使用,比如说配置列表,比如说一些固定的json,库存配置,地址配置,状态机配置,对于一般不怎么改动的且并发量在100
以内的使用注解配置要舒服的多,今天还是看了一下源码顺便把这个好用的缓存件总结下来。
spring
从3.1
就开始定义了Cache
和CaheManager 接口
来实现工程上面的缓存技术并支持JCache
注解来简化开发,具体内容可以参考spring
的官网文档。Cache
接口为缓存组件规范了定义,包含缓存的各种操作集合
;
源码
入门
关于缓存管理器接口,提供了 获取缓存,和通过名字获取缓存
缓存件里面提供了多种缓存中间件,有普通的也有组件化以及redis
等缓存管理器
通过当前map来管理不同名字的缓存
在赋予缓存名字的时候会根据是否存在命名,如果没有会创建当前map缓存
方法
由上文源码可以了解到
缓存 — 缓存管理器 – 缓存
springBoot 自动配置缓冲中间件。
通过注入缓存的搜索器去搜索各种缓存配置
通过mapping
来映射缓存类型配置
缓存类型配置由map集合
收纳
缓存类型枚举
文中以redis
为例 通过映射redis类
型获取 redis 缓存配置
通过源码可以看到构造函数 存在redisCacheConfiguration
如果不存在默认配置,通过bean
帮我们创建好了 CacheManager
管理器
从CacheProperties
Application
写入的Spring.Cache
里面注入过来的缓存名称。
Spring.Cache
配置
如果没有缓存名字会自己初始化一个缓存名称
拿到管理器之后确定配置 获取管理器配置
下面关于如果没有redisCacheConfigration
那么默认创建可以看到key
是String
序列号,值是JDK
序列号,如果后期脚本使用那么存储在redis
缓存的值需要进行再处理为json
从文中可以看到,缓存管理器以及缓存只要开启缓存,并配置简单的缓存类型,那么缓存中间件就可以自动化为我们配置好所需要的所有管理器,以及缓存
SpringBoot
已经启用自动化配置进行缓存封装,这种情况,以常用的redis
为例进行缓冲示例
介绍几个注解
@Cacheable
触发保存到缓存 常用@CacheEvict
触发将缓冲删除@CachePut
不影响方法执行更新@Cacheing
组合多个操作@CacheConfig
在类级别共享缓冲配置
整合SpringCache
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.3.2.RELEASE</version>
</dependency>
开启缓存
配置属性
spring.cache.type=redis
spring.cache.redis.time-to-live=6000
# 防止穿透
spring.cache.redis.cache-null-values=true
# 指定前缀 就用指定的前缀,如果没有默认使用缓存名字作为前缀
spring.cache.redis.key-prefix=cache_
spring.cache.redis.use-key-prefix=true
了解注解
录入测试文本
测试案例分析
@Cacheable
代表当前结果需要缓存 如果缓存中有 方法不需要调用 ,如果缓存没有查询结果映射到redis
缓存中去
@AliasFor("cacheNames")
String[] value() default {};
可能遇到的问题,击穿 雪崩 穿透
每个需要缓存的数据 指定业务类型 放到缓存分区管理器中,方便后期从redis
获取
缓存分区 CacheNames
缓存建 key = "#root.methodName"
方法名
配置文件 -> spring.cache.redis.key-prefix=cache_
缓存前缀 cache_
解决雪崩
spring.cache.redis.time-to-live=6000
过期时间 雪崩设置过期时间 6000
毫秒
解决穿透
spring.cache.redis.cache-null-values=true
穿透是否存储null
解决
击穿 设置 注解 sync = true
过期同步线程获取
@Cacheable(value = {"location"},key = "#root.methodName",sync = true)
自定义缓存
前面源码说到, 由于存储值进行的默认是JDK
序列, 如果没有RedisCacheConfiguration
才会创建
捋一下思路
CacheAutoConfiguration -> getConfigurationClass -> RedisCacheConfiguration ->cacheManager -> RedisCacheManager ->determineConfiguration -> 判断是否为空->
由于缓存的redis
过期时间为空 且 序列化方式为JDK
序列存储,所以建议定义存储 为 json
方便后面使用
源码构造配置
// 判断是否为空 ->
config.serializeValuesWith(SerializationPair
.fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
RedisCacheConfiguration(CacheProperties cacheProperties,
CacheManagerCustomizers customizerInvoker,
ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration) {
this.cacheProperties = cacheProperties;
this.customizerInvoker = customizerInvoker;
this.redisCacheConfiguration = redisCacheConfiguration.getIfAvailable();
}
改造
@EnableConfigurationProperties(CacheProperties.class)
@Configuration
public class MyCacheConfig {
/**
* @ConfigurationProperties(prefix = "spring.cache")
* public class CacheProperties {
*
* @return
*/
@Bean
RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
config.serializeKeysWith( RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
CacheProperties.Redis redisProperties = cacheProperties.getRedis();
if (redisProperties.getTimeToLive() != null) {
config = config.entryTtl(redisProperties.getTimeToLive());
}
if (redisProperties.getKeyPrefix() != null) {
config = config.prefixKeysWith(redisProperties.getKeyPrefix());
}
if (!redisProperties.isCacheNullValues()) {
config = config.disableCachingNullValues();
}
if (!redisProperties.isUseKeyPrefix()) {
config = config.disableKeyPrefix();
}
return config;
}
}
总结
读多写少 及时性 一致性要求不高的数据, 完全可以使用Srping - Cache
特殊情况需要强及时性及数据一致性,可以进行特殊设计