一、简介
1. Spring Cache是Spring提供的一个缓存框架,在Spring3.1版本开始支持将缓存添加到现有的spring应用程序中,在4.1开始,缓存已支持JSR-107注释和更多自定义的选项。
1. Spring Cache利用了**AOP**,实现了基于注解的缓存功能,并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,**只需要简单地加一个注解,就能实现缓存功能了,做到了对代码侵入性做小。**
1. 由于市面上的缓存工具实在太多,SpringCache框架还提供了CacheManager接口,可以实现降低对各种缓存框架的耦合。它不是具体的缓存实现,它只提供一整套的接口和代码规范、配置、注解等,用于整合各种缓存方案,比如Caffeine、Guava Cache、Ehcache、**Redis**。
二、常用注解
三、整合Redis
1、pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot </groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置(配置类添加@EnableCaching注解)
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Resource
private RedisConnectionFactory factory;
// 自定义key前缀,例如:cacheName=product.selectOne -> product.selectOne.
//SEPARATOR=#
@Bean
public CacheKeyPrefix cacheKeyPrefix() {
return cacheName -> cacheName + ".";
}
//key生成器
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
if (ObjectUtil.isBasicType(params[0]) || StrUtil.isEmptyIfStr(params[0])) {
for (Object param : params) {
sb.append(param.toString());//基本类型、字符串类型 key直接拼接
}
} else {
sb.append(JSONUtil.toJsonStr(params[0]));//对象类型拼接json字符串 {}
}
return sb.toString();
};
}
@Bean//序列化器
public Jackson2JsonRedisSerializer<Object> serializer() {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.registerModule(new ParameterNamesModule());
serializer.setObjectMapper(objectMapper);
return serializer;
}
@Bean
public RedisCacheManager redisCacheManager(Jackson2JsonRedisSerializer<Object> serializer) {
RedisSerializationContext<Object, Object> serializationContext = RedisSerializationContext.fromSerializer(serializer);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
.serializeValuesWith(serializationContext.getValueSerializationPair())//指定redis序列化器
.computePrefixWith(cacheKeyPrefix());//指定key前缀
return new CustomRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), redisCacheConfiguration);
}
static class CustomRedisCacheManager extends RedisCacheManager {
public static final String SEPARATOR = "#";
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
//name=product.selectOne#1800
String[] arr = StringUtils.delimitedListToStringArray(name, SEPARATOR);
name = arr[0];//name=product.selectOne
if (arr.length > 1) {
long ttl = Long.parseLong(arr[1]);
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
}
return super.createRedisCache(name, cacheConfig);
}
}
}
四、使用
直接在Controller上添加注解
@GetMapping
@Cacheable(value = "product.select#3600")
public List<Product> select(ProductQuery query) {
return productDao.sel;ect(query);
}
@GetMapping("{id}")
@Cacheable(value = "product.selectById#1800")
public Product selectById(@PathVariable Integer id) {
return productService.selectOne(id);
}
key示例
五、其他配置
1、缓存击穿配置
@Cacheable(value = "product.selectOne#1800",sync = true)
2、缓存穿透(缓存空值?默认开启)
#spring.cache.redis.cache-null-values=true
# 配置2(Controller直接配置时间)
@GetMapping
@Cacheable(value = "3600")
public List<Product> select(ProductQuery query) {
return productDao.select(query);
}
@GetMapping("{id}")
@Cacheable(value = "1800",sync = true)
public Product selectById(@PathVariable Integer id) {
return productService.selectOne(id);
}
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Resource
private RedisConnectionFactory factory;
// 自定义key前缀,例如:cacheName=product.selectOne -> product.select.
//SEPARATOR=#
// @Bean
// public CacheKeyPrefix cacheKeyPrefix() {
// return cacheName -> cacheName + "#";
// }
//key生成器
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName()).append(".");
sb.append(method.getName()).append(".");
if (ObjectUtil.isBasicType(params[0]) || StrUtil.isEmptyIfStr(params[0])) {
for (Object param : params) {
sb.append(param.toString());//基本类型、字符串类型 key直接拼接
}
} else {
sb.append(JSONUtil.toJsonStr(params[0]));//对象类型拼接json字符串 {}
}
return sb.toString();
};
}
@Bean//序列化器
public Jackson2JsonRedisSerializer<Object> serializer() {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.registerModule(new ParameterNamesModule());
serializer.setObjectMapper(objectMapper);
return serializer;
}
@Bean
public RedisCacheManager redisCacheManager(Jackson2JsonRedisSerializer<Object> serializer) {
RedisSerializationContext<Object, Object> serializationContext = RedisSerializationContext.fromSerializer(serializer);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
.disableKeyPrefix()//禁用前缀
.serializeValuesWith(serializationContext.getValueSerializationPair());//指定redis序列化器
//.computePrefixWith(cacheKeyPrefix()); //指定key前缀cacheable.cacheResolver()
return new CustomRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), redisCacheConfiguration);
}
static class CustomRedisCacheManager extends RedisCacheManager {
//public static final String SEPARATOR = "#";
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
//name=product.selectOne#1800
//String[] arr = StringUtils.delimitedListToStringArray(name, SEPARATOR);
//if (arr.length > 1) {
long ttl = Long.parseLong(name);
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
//}
return super.createRedisCache(name, cacheConfig);
}
}
}
标签:缓存,return,Spring,Cache,serializer,使用,new,public,objectMapper
From: https://blog.csdn.net/zhzjn/article/details/142406286