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,转载请注明。