开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情
一,介绍
SpringBoot 的缓存可以使用本地缓存,也可以整合第三方缓存,比如:redis、guava、ehcahe、jcache等等。 接下来主要介绍SpringBoot的缓存整合Redis的使用。
注:下面介绍的方式主要是通过注解来进行缓存的使用,当然,你还可以使用RedisTemplate来操作Reids缓存在pom.xml中添加以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
二,本地缓存
2.1概念
Java Caching定义了五个核心接口,分别是CachingProvider、CachingManager、Cache、Entry、Expiry
- CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
- CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
- Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
- Entry是一个存储在Cache中的key-value对。
- Expiry每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。
2.2几个重要的缓存注解
@EnableCaching 开启基于注解的缓存; 可以加在主运行类上,也可以加在配置类上;
@EnableCaching
@SpringBootApplication
public class DelespringApplication {
public static void main(String[] args) {
SpringApplication.run(DelespringApplication.class, args);
}
}
@EnableCaching
@Configuration
public class RedisConfig{
}
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其进行缓存
@Cacheable(value = "cach1")
@RequestMapping("list")
public List<Student> fun(Integer id,Integer age) {
List<Student> list = studentMapper.selectList(null);
return list;
}
常用参数:
value/cacheNames 缓存的名称,也是缓存的命名空间
key 缓存的键,可以为空,如果指定要按照 SpEL 表达式编写; 默认的key
- 单参数:cacheNames::arg
- 无参数: cacheNames::SimpleKey [], 后面使用 SimpleKey []来补齐
- 多参数: cacheNames::SimpleKey [arg1, arg2…]
- 非基础对象:cacheNames::obj.toString()
使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如: @Cacheable(value="users", key="#id") @Cacheable(value="users", key="#p0") keyGenerator 缓存键的生成器
@Configuration
public class MyConfig extends CachingConfigurerSupport {
@Autowired
private RedisConnectionFactory factory;
@Bean
public KeyGenerator keyGenerator(){
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
String name = method.getName();
return name;
}
};
}
}
@RestController
public class MyController {
@Autowired
private StudentMapper studentMapper;
@Cacheable(value = "cach1",keyGenerator = "keyGenerator")
@RequestMapping("list")
public List<Student> fun(Integer id,Integer age) {
List<Student> list = studentMapper.selectList(null);
return list;
}
}
- cacheManager 缓存管理器,用法同上。
- condition 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)
- unless 否定缓存。当条件结果为TRUE时,就不会缓存。@Cacheable(value=”testcache”,unless=”#userName.length()>2”)
@CachePut 保证方法被调用,又希望结果被缓存。与@Cacheable区别在于是否每次都调用方法,常用于更新,常用参数和 @Cacheable 大致一样
@CacheEvict 清空缓存 常用参数:
- allEntries 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如:@CachEvict(value=”testcache”,allEntries=true)
- beforeInvocation 是否在方法执行前就清空,缺省为 false,如果指定为 true,
@CacheConfig 该注解可以统一设置缓存的名称,它是类级别的注解方式。 注意:如果同时使用了 @CacheConfig 和 @Cacheable ,则将优先使用
@CacheConfig(cacheNames = "renqiang")
@RestController
public class MyController {
@Autowired
private StudentMapper studentMapper;
// 优先使用此缓存名称
@Cacheable(value = "qiang")
@RequestMapping("list")
public List<Student> fun(Integer id,Integer age) {
List<Student> list = studentMapper.selectList(null);
return list;
}
}
@Caching 使用以上注解的时候,每一个注解都需要一个方法,如果要实现一个方法同时满足多个缓存注解的时候,就可以使用此注解。 从源码可以看出来,此注解是 @Cacheable,@CachePut,@CacheEvict 的结合体
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
Cacheable[] cacheable() default {};
CachePut[] put() default {};
CacheEvict[] evict() default {};
}
例子:
@RestController
public class MyController {
@Autowired
private StudentMapper studentMapper;
@Caching(
cacheable = {@Cacheable(value = "ren")},
put = {
@CachePut(value = "ren1",key = "#id"),
@CachePut(value = "ren2",key = "#age")
}
)
@RequestMapping("list")
public List<Student> fun(Integer id,Integer age) {
List<Student> list = studentMapper.selectList(null);
return list;
}
}
三,相关配置
1,自定义 key 第一种方法,继承CachingConfigurerSupport类,重写 KeyGenerator 方法
@Configuration
public class MyConfig extends CachingConfigurerSupport {
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
}
第二种方法,实现KeyGenerator接口
@Configuration
public class MyConfig implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
return null;
}
}
使用
@RestController
public class MyController {
@Autowired
private StudentMapper studentMapper;
@Cacheable(value = "cah1",keyGenerator = "myConfig")
@RequestMapping("fun1")
public List fun1(){
List<Student> list = studentMapper.selectList(null);
return list;
}
}
2,自定义缓存过期时间 第一种方法,继承CachingConfigurerSupport类,重写 cacheManager 方法
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisConnectionFactory factory;
@Override
public CacheManager cacheManager() {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration configuration1 = configuration
.entryTtl(Duration.ofSeconds(20)) // 设置过期事件为20秒
.disableCachingNullValues() // 不缓存空值
// .disableKeyPrefix() // 不使用缓存前缀
.prefixCacheNameWith("ren"); // 自定义缓存前缀
RedisCacheManager build = RedisCacheManager.builder(factory)
.cacheDefaults(configuration1)
.build();
return build;
}
}
第二种方法,配置类
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Bean
public CacheManager cacheManager() {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration configuration1 = configuration.entryTtl(Duration.ofSeconds(20))
.disableCachingNullValues();
// 设置一个初始化的缓存空间set集合
Set<String> cacheNames = new HashSet<>();
cacheNames.add("cah1");
cacheNames.add("cah2");
// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("cah1", configuration1); // 使用默认的缓存时间
configMap.put("cah2", configuration.entryTtl(Duration.ofSeconds(10))); // cah2 缓存空间的缓存时间
RedisCacheManager build = RedisCacheManager
.builder(factory)
.initialCacheNames(cacheNames) // 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
.withInitialCacheConfigurations(configMap)
.build();
return build;
}
}
3,自定义序列化方式
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory factory;
@Bean
public CacheManager cacheManager() {
//初始化一个RedisCacheWriter
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(factory);
Jackson2JsonRedisSerializer jsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
RedisSerializationContext.SerializationPair serializationPair = RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer);
// RedisCacheConfiguration默认是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value
// 设置 key 的序列化方式为 jackson
RedisCacheConfiguration configuration1 = RedisCacheConfiguration.defaultCacheConfig().serializeKeysWith(serializationPair);
// 设置 value 的序列化方式为 jackson
RedisCacheConfiguration configuration2 = configuration1.serializeValuesWith(serializationPair);
// 设置过期时间为 20 秒
RedisCacheConfiguration configuration3 = configuration2.entryTtl(Duration.ofSeconds(20));
RedisCacheManager manager = new RedisCacheManager(redisCacheWriter, configuration3);
return manager;
}
}