spring使用RedisCacheManager管理key的一些问题

spring可以很好地管理各种内存的快速缓存。

这些常见的内存缓存库实现方式有redis,Ehcache。

本文阐述的是redis,毕竟这个东西相当容易使用。

 

spring通过 org.springframework.cache.Cache 和org.springframework.cache.CacheManager两个接口来管理缓存

redis的cache实现类是 RedisCacheManager,它们的关系是这样的:

object

   <-AbstractCacheManager=>(CacheManager, InitializingBean)

       <-AbstractTransactionSupportingCacheManager

          <-RedisCacheManager

可以看出RedisCacheManager实现了接口CacheManager接口。

一、如何自定义redis中key

如果使用默认的方式来注册RedisCacheManager,如下:

RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(this.cacheTimeOutHour))

假定注解是这样的:

@Cacheable(value="getUserPoJoById",key="#userId")

那么生成redis的key是形如这样的:

getUserPoJoById::103

其中双冒号(::)是分隔符。

这是因为RedisCacheConfiguration.defaultCacheConfig()的源码如下:

 

public static RedisCacheConfiguration defaultCacheConfig() {
        return defaultCacheConfig(null);
    }
public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {

        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();

        registerDefaultConverters(conversionService);

        return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(),
                SerializationPair.fromSerializer(RedisSerializer.string()),
                SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
    }

 

从上面代码可以看到使用的key前缀是CacheKeyPrefix.simple(),CacheKeyPrefix.simple()的实现如下:

 

@FunctionalInterface
public interface CacheKeyPrefix {

    /**
     * Compute the prefix for the actual {@literal key} stored in Redis.
     *
     * @param cacheName will never be {@literal null}.
     * @return never {@literal null}.
     */
    String compute(String cacheName);

    /**
     * Creates a default {@link CacheKeyPrefix} scheme that prefixes cache keys with {@code cacheName} followed by double
     * colons. A cache named {@code myCache} will prefix all cache keys with {@code myCache::}.
     *
     * @return the default {@link CacheKeyPrefix} scheme.
     */
    static CacheKeyPrefix simple() {
        return name -> name + "::";
    }
}

 simple实现的CacheKeyPrefix的compute方法等同于:

String compute(String cacheName){

   return cacheName+"::";

}

 

所以默认的是使用双冒号进行分隔。

 

但很多情况下,我们并不希望redis的key就是这样的形式,我们可能想:

  1. 在整个key前加前缀
  2. 使用不同的分隔符号

怎么做了? 调用CacheKeyPrefix 的定制实现即可。

先来看看CacheKeyPrefix 的唯一接口方法(非静态):

String compute(String cacheName);

也就是说我们可以通过compute来指定需要的实现。

思路有了,那么以下就是实现方式:

 

RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofHours(this.cacheTimeOutHour)).computePrefixWith(cacheName -> cacheName + this.keyPrefix);
        RedisCacheManager cm=RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(redisCacheConfiguration).build();
        cm.setTransactionAware(true);

 

上文中的关键代码部分:computePrefixWith(cacheName -> cacheName + this.keyPrefix);

我们来看下RedisCacheConfiguration的computePrefixWith的实现代码:

public RedisCacheConfiguration computePrefixWith(CacheKeyPrefix cacheKeyPrefix) {

        Assert.notNull(cacheKeyPrefix, "Function for computing prefix must not be null!");

        return new RedisCacheConfiguration(ttl, cacheNullValues, true, cacheKeyPrefix, keySerializationPair,
                valueSerializationPair, conversionService);
    }

所以代码:cacheName -> cacheName + this.keyPrefix 就是为了构建CacheKeyPrefix的compute方法

 

String compute(String cacheName){

   return cacheName+this.keyPrefix;

}

 

 

如果想加前缀,可以这样:

computePrefixWith(cacheName -> this.getCachePrefix+"->"+cacheName + this.keyPrefix)
这等同于compute方法变为: return this.getCachePrefix+"->"+cacheName + this.keyPrefix

 

 

spring 5.1.x后大量使用lambda,如果不熟悉,就无法阅读这个代码。

 

二、定义key所需要注意的其它方面

1.当多个应用共用一个redis实例的时候,需要注意使用前缀

2.如果有很多值,建议key短一些,并形成一个key的命名文档

posted @ 2020-03-10 23:56  正在战斗中  阅读(6806)  评论(0编辑  收藏  举报