spring cache无法设置key过期时间解决

351 阅读2分钟

回顾Spring cache使用

1. 引用依赖

<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注解

3.使用

在需要的方法上加@Cacheable注解,需要注意@Cacheable的几个参数:

  • value、cacheNames: 两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项。
  • key: 缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = “#p0”):使用函数第一个参数作为缓存的key值

解决问题

可以看出@Cacheable并没有设置过期时间的参数。解决办法:

配置CacheManager:
@Getter
public enum CacheEnums {

    /**
     * 查询用户信息
     */
    SELECT_BY_USERNAME("user/select/selectByUsername","查询用户信息",20),
    ;
    /**
     * cacheNames
     */
    @Getter
    final String cacheNames;
    /**
     * 描述
     */
    @Getter
    final String desc;

    /**
     * 有效时间 单位秒
     */
    @Getter
    final long ttl;

    CacheEnums( String cacheNames,String desc,long ttl) {
        this.cacheNames = cacheNames;
        this.desc = desc;
        this.ttl = ttl;
    }

    public static CacheEnums getByValue(String cacheNames) {
        for (CacheEnums e : values()) {
            if (e.cacheNames.compareTo(cacheNames) == 0) {
                return e;
            }
        }
        return null;
    }
}

@Configuration
@EnableCaching
public class RedisCacheConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }


    /**
     * @param template
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate<String, Object> template) {

        RedisCacheManager.RedisCacheManagerBuilder managerBuilder = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(Objects.requireNonNull(template.getConnectionFactory()))
                // 缓存配置
                .cacheDefaults(getCacheTtlConfiguration(template, 60 * 60));
        for (CacheEnums e : CacheEnums.values()) {
            managerBuilder.withCacheConfiguration(e.getCacheNames(), getCacheTtlConfiguration(template, e.getTtl()));
        }
        return managerBuilder
                // 配置同步修改或删除 put/evict
                .transactionAware()
                .build();
    }

    public RedisCacheConfiguration getCacheTtlConfiguration(RedisTemplate<String, Object> template, long seconds) {

        return RedisCacheConfiguration
                .defaultCacheConfig()
                // 设置key为String
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))
                // 设置value 为自动转Json的Object
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))
                // 不缓存null
                .disableCachingNullValues()
                // 缓存数据保存1小时
                .entryTtl(Duration.ofSeconds(seconds));
    }
}
  • getCacheTtlConfiguration()方法可以配置CacheConfiguration的有效时间。
  • 将该CacheConfiguration作为参数放到managerBuilder.withCacheConfiguration()中,就实现了对缓存的有效时间配置。
  • 维护了一个CacheEnums的枚举,避免了修改该配置类,直接在枚举中配置。
  • 记得在配置类上加上@EnableCaching注解,当然也可以把这个CacheManager的Bean放到启动类下。
  • 枚举中的cacheNames就是@Cacheable中参数value、cacheNames的内容,可以将一系列类似的缓存配置一样的有效时间。