拡張spring cacheはキャッシュマルチテナントとその自動期限切れをサポートする


Spring cacheの概念
Springは、本質的にはEHCacheやOSCacheなどの特定のキャッシュ実装スキームではなく、既存のコードに定義された様々なannotationを少量追加することで、キャッシュメソッドの戻りオブジェクトの効果を達成することができる、アノテーションベースのキャッシュ技術をサポートする.
  • @Cacheableの使用効果により、cacheName+要求インパラメータ(key)からなるredisに保存されたkey
  • public class PigxClientDetailsService extends JdbcClientDetailsService {
        @Cacheable(value = SecurityConstants.CLIENT_DETAILS_KEY, key = "#clientId")
        public ClientDetails loadClientByClientId(String clientId) {
            return super.loadClientByClientId(clientId);
        }
    }}

    マルチテナントでのキャッシュの問題分析
  • デフォルトAテナントインパラメータはK 1リクエストアプリケーションであり、spring cacheはK 1の値を自動的にキャッシュし、BテナントインパラメータがK 1リクエストアプリケーションである場合、spring cacheは同じRedis K 1上のクエリーデータに自動的に関連付けられます.
  • マルチテナントの下でA/Bテナントが要求するK 1は同じパラメータではなく(パラメータ名パラメータ値は同じように見えるが)、同じ結果を返すことはできない.
  • デフォルトのspring cacheは、パラメータに基づいてマルチテナントシステムの設計要件を満たすことができず、テナントによる隔離を実現できないことを区別します.

  • 区分キャッシュ増加テナントID
  • AテナントはK 1に登録され、spring cacheはRedis Keyがテナント情報
  • を接続することを維持する.
  • KEY=cacheName+入参+テナントID
  • このようなA/Bテナント要求パラメータとは同時に、読み出したものも異なるKeyの中の値であり、データの汚れた読み取りを回避し、隔離型
  • を保証する.

  • Spring CacheのcacheManagerキャッシュを書き換える
  • コンテキストからテナントIDを取得し、@Cacheable value値を書き換えると完了し、このcacheManager
  • に注入する.
    @Slf4j
    public class RedisAutoCacheManager extends RedisCacheManager {
        /**
         *          ID,  @Cacheable value  
         * @param name
         * @return
         */
        @Override
        public Cache getCache(String name) {
            return super.getCache(TenantContextHolder.getTenantId() + StrUtil.COLON + name);
        }
    }
  • なぜStrUtil.COLOONである':'分割
  • GUIツールでは、':'の区切り文字でグループ化され、より効果的に表示されます.
    スプリングcacheのアクティブな期限切れ機能を追加
  • デフォルトの注記には、次の図
  • のように時間に関するパラメータはありません.
    public @interface Cacheable {
    
        @AliasFor("cacheNames")
        String[] value() default {};
    
        @AliasFor("value")
        String[] cacheNames() default {};
    
        String key() default "";
    
        String keyGenerator() default "";
    
        String cacheManager() default "";
    
        String cacheResolver() default "";
    
        String condition() default "";
    
        String unless() default "";
    
        boolean sync() default false;
    
    }
    
  • またはvalueを入口とするvalue="menu_details#2000"は、vaueに数字を追加して特殊文字で分割することにより、期限切れとして
  • を参照する.
    @Service
    @AllArgsConstructor
    public class PigXMenuServiceImpl extends ServiceImpl implements SysMenuService {
        private final SysRoleMenuMapper sysRoleMenuMapper;
    
        @Override
        @Cacheable(value = "menu_details#2000", key = "#roleId  + '_menu'")
        public List findMenuByRoleId(Integer roleId) {
            return baseMapper.listMenusByRoleId(roleId);
        }
    }
  • cachemanager別の重要なメソッドを書き換えてキャッシュを作成するメソッドです.valueで設定された期限切れを切り取ることで、RedisCacheConfiguration
  • に値を割り当てます.
    public class RedisAutoCacheManager extends RedisCacheManager {
        private static final String SPLIT_FLAG = "#";
        private static final int CACHE_LENGTH = 2;
    
        @Override
        protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) {
            if (StrUtil.isBlank(name) || !name.contains(SPLIT_FLAG)) {
                return super.createRedisCache(name, cacheConfig);
            }
    
            String[] cacheArray = name.split(SPLIT_FLAG);
            if (cacheArray.length < CACHE_LENGTH) {
                return super.createRedisCache(name, cacheConfig);
            }
    
            if (cacheConfig != null) {
                long cacheAge = Long.parseLong(cacheArray[1]);
                cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(cacheAge));
            }
            return super.createRedisCache(name, cacheConfig);
        }
    }
  • spring cache操作キャッシュ時に前のステップで設定したttl付与をkey
  • に取得する.
        @Override
        public void put(Object key, @Nullable Object value) {
    
            Object cacheValue = preProcessCacheValue(value);
    
            if (!isAllowNullValues() && cacheValue == null) {
    
                throw new IllegalArgumentException(String.format(
                        "Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable(unless=\"#result == null\")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.",
                        name));
            }
    
            cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl());
        }

    まとめ
  • spring cacheの拡張により、キャッシュに対するいくつかの透明な操作
  • を実現することができる.
  • cachemanagerはspringcacheが対外的に提供するAPI拡張エントリ
  • である.
  • 以上のソースコードリファレンス個人プロジェクトSpring Cloud、OAuth 2.0に基づいてVue前後分離に基づく開発プラットフォーム
  • を開発する.
  • QQ:2270033969 spring cloudの使い方について話しましょう.
  • 私たちの公衆番号に注目してもっと面白いJavaEE実践
  • を獲得することを歓迎します.