zoukankan      html  css  js  c++  java
  • 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的命名文档

  • 相关阅读:
    java.security.ProviderException: java.security.KeyException
    DES ECB 模式 JAVA PHP C# 实现 加密 解密 兼容
    mysql timestamp类型字段的CURRENT_TIMESTAMP与ON UPDATE CURRENT_TIMESTAMP属性
    阿里云composer 镜像
    封装redis操作 php版本
    金钱数友好显示 php版本
    php代码规范->如何写出规范且易于理解的项目代码-ZX版
    hibernate 注解大全
    国家省市区县乡镇三级,五级地址数据
    java基础 数据类型转换
  • 原文地址:https://www.cnblogs.com/lzfhope/p/12459759.html
Copyright © 2011-2022 走看看