一,介绍
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")
SpEL上下文数据
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root对象 | 当前被调用的方法名 | #root.methodname |
method | root对象 | 当前被调用的方法 | #root.method.name |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
Argument Name | 执行上下文 | 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 | #artsian.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
SpEL提供了多种运算符
关系 | <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne |
---|---|
类型 | 运算符 |
算术 | +,- ,* ,/,%,^ |
逻辑 | &&,!,and,or,not,between,instanceof |
条件 | ?: (ternary),?: (elvis) |
正则表达式 | matches |
其他类型 | ?.,?[…],![…],^[…],$[…] |
- 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 ,则将优先使用 @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接口
/**
* @Author: Esyrg
* @Date: 2022/6/11 23:15
*/
@Configuration
public class MyConfig implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
return null;
}
}
使用
/**
* @Author: Esyrg
* @Date: 2022/6/11 22:25
*/
@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 方法
/**
* @Author: Esyrg
* @Date: 2022/8/22 21:41
*/
@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;
}
}
第二种方法,配置类
/**
* @Author: Esyrg
* @Date: 2022/8/22 21:41
*/
@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,自定义序列化方式
/**
* @Author: Esyrg
* @Date: 2022/8/22 21:41
*/
@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;
}
}