Spring Cache Redis缓存key生成策略

今天有人问我为什么我之前使用spring cache redis时,redis里面的key是cacheName::cacheKey格式,而现在cacheName的前缀没了?下面我们来分析一下key的生成逻辑。

源码分析

Spring Boot应用启动时,会自动加载redis相关的配置。我们主要关注一下RedisCacheConfiguration类。该类会创建一个RedisCacheManager。

@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
      ResourceLoader resourceLoader) {
   RedisCacheManagerBuilder builder = RedisCacheManager
         .builder(redisConnectionFactory)
         .cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));@1
   List<String> cacheNames = this.cacheProperties.getCacheNames();
   if (!cacheNames.isEmpty()) {
      builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
   }
   return this.customizerInvoker.customize(builder.build());
}

代码@1:通过Builder模式构建一个RedisCacheManagerBuilder。创建RedisCacheManagerBuilder会通过determineConfiguration()方法传入redis默认的配置。

private org.springframework.data.redis.cache.RedisCacheConfiguration determineConfiguration(
      ClassLoader classLoader) {
   if (this.redisCacheConfiguration != null) {
      return this.redisCacheConfiguration;
   }
   Redis redisProperties = this.cacheProperties.getRedis();
   org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration
         .defaultCacheConfig(); @1
   config = config.serializeValuesWith(SerializationPair
         .fromSerializer(new JdkSerializationRedisSerializer(classLoader)));
   if (redisProperties.getTimeToLive() != null) {
      config = config.entryTtl(redisProperties.getTimeToLive());
   }
   if (redisProperties.getKeyPrefix() != null) {
      config = config.prefixKeysWith(redisProperties.getKeyPrefix()); @2
   }
   if (!redisProperties.isCacheNullValues()) {
      config = config.disableCachingNullValues();
   }
   if (!redisProperties.isUseKeyPrefix()) {
      config = config.disableKeyPrefix(); @3
   }
   return config;
}

public RedisCacheConfiguration prefixKeysWith(String prefix) {

		Assert.notNull(prefix, "Prefix must not be null!");

		return computePrefixWith((cacheName) -> prefix);
	}

代码@1:创建一个默认的RedisCacheConfiguration。这里会定义一个默认的CacheKeyPrefix的实现CacheKeyPrefix.simple(),simple()方法其实就是返回了一个"cacheName::"字符串。

代码@2:如果key前缀不为空,设置key前缀。该方法就是返回一个CacheKeyPrefix实现为(cacheName) -> prefix的RedisCacheConfiguration。这里就可以看出,如果你开启了使用key前缀开关,并且你的key前缀不为空,默认的CacheKeyPrefix.simple()实现就被替换为(cacheName) -> prefix,此时,你的key前缀就不会用使用缓存名了。

代码@3:如果不允许使用key前缀,则关闭key前缀。

当调用RedisCache中方法时,用到缓存key的地方都会经过createAndConvertCacheKey方法。

private byte[] createAndConvertCacheKey(Object key) {
   return serializeCacheKey(createCacheKey(key));@1
}

代码@1:序列化缓存key。

protected String createCacheKey(Object key) {
   String convertedKey = convertKey(key);@1
   if (!cacheConfig.usePrefix()) {@2
      return convertedKey;
   }
   return prefixCacheKey(convertedKey);@3
}

代码@1:将key转为字符串。

代码@2:判断是否开启使用前缀开关,如果没开启,直接返回key作为缓存key。

代码@3:返回带有前缀的缓存key。

private String prefixCacheKey(String key) {
   // allow contextual cache names by computing the key prefix on every call.
   return cacheConfig.getKeyPrefixFor(name) + key;@1
}

代码@1:调用RedisCacheConfiguration中的CacheKeyPrefix获取前缀,再拼接传入的key作为缓存的key。

总结:

1、RedisCacheConfiguration#defaultCacheConfig()方法创建一个RedisCacheConfiguration,默认CacheKeyPrefix实现是CacheKeyPrefix.simle(),也就是返回一个“cacheName::”字符串作为前缀。

2、当开启了使用key前缀(spring.cache.redis.use-key-prefix=true)并且配置的key前缀(spring.cache.redis.key-prefix=xxx)不为空时,RedisCacheConfiguration使用(cacheName) -> prefix作为CacheKeyPrefix实现,此时你返回的前缀的值就是你定义的prefix字符串。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值