SpringCache缓存框架介绍
- SpringCache简介
- 文档:https://spring.io/guides/gs/caching/
- 自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象
- 提供基本的Cache抽象,方便切换各种底层Cache
- 只需要更少的代码就可以完成业务数据的缓存
- 提供事务回滚时也自动回滚缓存,支持比较复杂的缓存逻辑
- 核心
- 一个是Cache接口,缓存操作的API;
- 一个是CacheManager管理各类缓存,有多个缓存框架的实现
- 讲课方式
- 很多其他地方的教程,使用单元测试的方式教SpringCache使用
- 多个同学反馈看了也不懂在SpringBoot或者Cloud微服务项目中使用
- 本章内容采用案例实战的方式,教大家怎么使用,工作中开发项目直接采用即可
- 学会触类旁通,举一反三
- 使用
- 项目中引入starter
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
配置设置
Redis必不可少
spring:
#指定缓存的类型
cache:
type: redis 启动类添加
@EnableCaching
需要一个自定义CacheManager配置
package net.xdclass.xdclassredis.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.time.Duration;
@Configuration
public class AppConfiguration {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置key和value的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// 设置hashKey和hashValue的序列化规则
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
// 设置支持事物
//redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 新的分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
/**
* 1分钟过期
*
* @param connectionFactory
* @return
*/
@Bean
public RedisCacheManager cacheManager1Minute(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = instanceConfig(60L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
/**
* 默认是1小时
*
* @param connectionFactory
* @return
*/
@Bean
@Primary
public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = instanceConfig(3600L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
/**
* 1天过期
*
* @param connectionFactory
* @return
*/
@Bean
public RedisCacheManager cacheManager1Day(RedisConnectionFactory connectionFactory) {
RedisCacheConfiguration config = instanceConfig(3600 * 24L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
private RedisCacheConfiguration instanceConfig(Long ttl) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
// 去掉各种@JsonSerialize注解的解析
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
// 只针对非空的值进行序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 将类型序列化到属性json字符串中
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(ttl))
//.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
}
/**
* 自定义缓存key规则
* @return
*/
@Bean
public KeyGenerator springCacheCustomKeyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object o, Method method, Object... objects) {
String key = o.getClass().getSimpleName() + "_" + method.getName() + "_" + StringUtils.arrayToDelimitedString(objects, "_");
System.out.println(key);
return key;
}
};
}
}
举两个小例子看看
@Override
@Cacheable(value = {"product"},key = "#root.args[0]",cacheManager = "cacheManager1Minute")
//@Cacheable(value = {"product"}, keyGenerator = "springCacheCustomKeyGenerator",cacheManager = "cacheManager1Minute")
public ProductDO findById(int id) {
return productMapper.selectById(id);
}
@Override
//@Cacheable(value = {"product_page"},key = "#root.methodName+'_'+#page+'_'+#size")
@Cacheable(value = {"product_page"},keyGenerator = "springCacheCustomKeyGenerator")
public Map<String, Object> page(int page, int size) {
Page pageInfo = new Page<>(page,size);
IPage<ProductDO> iPage = productMapper.selectPage(pageInfo,null);
Map<String,Object> pageMap = new HashMap<>(3);
pageMap.put("total_record",iPage.getTotal());
pageMap.put("total_page",iPage.getPages());
pageMap.put("current_data",iPage.getRecords());
return pageMap;
} 解析
value = {"product"}
定义缓存名字
#root.args[0]
获取第一个参数
key = "#root.methodName+'_'+#page+'_'+#size"
按照参数名字来进行区分
keyGenerator = "springCacheCustomKeyGenerator"
如果我们需要更新缓存,那么我们看下面的例子
@Override
@CachePut(value = {"product"},key="#productDO.id", cacheManager = "cacheManager1Minute")
public ProductDO updateById(ProductDO productDO) {
productMapper.updateById(productDO);
return productDO;
}
删除缓存的情况
@Override
@CacheEvict(value = {"product"},key = "#root.args[0]")
public int delById(int id) {
return productMapper.deleteById(id);
} 多个注解
@Override
//@Cacheable(value = {"product"},key = "#root.args[0]",cacheManager = "cacheManager1Minute")
//@Cacheable(value = {"product"}, keyGenerator = "springCacheCustomKeyGenerator",cacheManager = "cacheManager1Minute")
@Caching(
cacheable = {
@Cacheable(value = {"product"},key = "#root.args[0]"),
@Cacheable(value = {"product"},key = "'xdclass_'+#root.args[0]")
},
put = {
@CachePut(value = {"product_test"},key="#id", cacheManager = "cacheManager1Minute")
}
)
public ProductDO findById(int id) {
return productMapper.selectById(id);
} 本文作者为DBC,转载请注明。
