一、简介
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 {@Resourceprivate RedisConnectionFactory factory;// 自定义key前缀,例如:cacheName=product.selectOne -> product.selectOne.//SEPARATOR=#@Beanpublic CacheKeyPrefix cacheKeyPrefix() {return cacheName -> cacheName + ".";}//key生成器@Beanpublic 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;}@Beanpublic 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);}@Overrideprotected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {//name=product.selectOne#1800String[] arr = StringUtils.delimitedListToStringArray(name, SEPARATOR);name = arr[0];//name=product.selectOneif (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 {@Resourceprivate RedisConnectionFactory factory;// 自定义key前缀,例如:cacheName=product.selectOne -> product.select.//SEPARATOR=#
// @Bean
// public CacheKeyPrefix cacheKeyPrefix() {
// return cacheName -> cacheName + "#";
// }
//key生成器@Beanpublic 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;}@Beanpublic 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);}@Overrideprotected 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);}}}