springmvc redis @Cacheable擴充套件(一)

要吃西藍花發表於2021-03-09

springmvc 中有自帶的cache處理模組,可以是方法級別的快取處理,那麼在實際使用中,很可能自己造輪子,因為實際中永遠會有更奇怪的需求點。比如:
1 清除快取時候,能模糊的進行刪除
2 針對不同的key,設定不同的過期時間
這2個是有些麻煩的需求,當然針對快取內容,設定 key(這個 key 的確定)更讓人難受,不好取捨,需要有一定的開發經驗,否則只能不停的修改。
我們先集中處理第一個問題,模糊刪除

  • 1.查詢方案
  • 2.檢視低版本redis實現
  • 3.具體處理方式

明確問題,查詢方案

可能網上有不少的解決方案

  1. 直接重寫 https://blog.csdn.net/Crystalqy/article/details/110681684
  2. spring 5 + 版本的 https://my.oschina.net/u/220938/blog/3196609
  3. 具有啟發性的 https://blog.csdn.net/yali_aini/article/details/89923548

1. 首先我們從網上找到對應的修改的code,真的就是拿來就能用的那種,然後發現有2個function沒有,然後就發現你是低版本,然後就沒然後了。。

    <properties>
        <org.springframework-version>4.2.2.RELEASE</org.springframework-version>
        <org.aspectj-version>1.8.2</org.aspectj-version>
        <org.slf4j-version>1.7.21</org.slf4j-version>
        <org.log4j2-version>2.8.2</org.log4j2-version>
    </properties>

2. 根據第三個,可以看到,基於 redis template 的快取處理,是有模糊處理的方法的,也就是說,可以做模糊處理。

3. 檢視 spring 低版本 4.2.2 版本的 cache 的redis 類,進行簡單的 仿做


檢視低版本redis實現

因為使用springmvc時候,都會對 redis 進行配置,設定 ttl 等引數,那麼,點進去看原始碼,就會發現
CustomizedRedisCacheManagerCustomizeRedisCache ,和 高版本的名字很像,那麼仔細看看,發現 CustomizeRedisCache 就是需要改造的。

  public void evict(RedisCacheElement element)
  public void evict(Object key) 

這2個函式。很可以,2個檔案貼上出來,直接做成注入,發現就直接可以在 @Cacheable 的時候斷點看了。
這2個就是在刪除快取時候使用的。


改造一波

程式碼進行了刪減,需要修改後的,可以聯絡我

CustomizedRedisCacheManager


/**
 * CustomizedRedisCacheManager
 *
 * @desc  重新定義 oldcache 的 處理方式
 */

public class CustomizedRedisCacheManager extends RedisCacheManager {
    
    protected RedisOperations getRedisOperations() {
        return this.redisOperations;
    }

    protected RedisCachePrefix getCachePrefix() {
        return this.cachePrefix;
    }

    protected boolean isUsePrefix() {
        return this.usePrefix;
    }

    public void afterPropertiesSet() {
        if (!CollectionUtils.isEmpty(this.configuredCacheNames)) {
            Iterator var1 = this.configuredCacheNames.iterator();

            while (var1.hasNext()) {
                String cacheName = (String) var1.next();
                this.createAndAddCache(cacheName);
            }

            this.configuredCacheNames.clear();
        }

        super.afterPropertiesSet();
    }

    protected Cache decorateCache(Cache cache) {
        return this.isCacheAlreadyDecorated(cache) ? cache : super.decorateCache(cache);
    }

    protected boolean isCacheAlreadyDecorated(Cache cache) {
        return this.isTransactionAware() && cache instanceof TransactionAwareCacheDecorator;
    }
}

CustomizeRedisCache


/**
 * RedisCacheResolver
 *
 * @desc springCache 的過載
 */
public class CustomizeRedisCache extends RedisCache {
    private final RedisOperations redisOperations;
    private final CustomizeRedisCache.RedisCacheMetadata cacheMetadata;
    private final CacheValueAccessor cacheValueAccessor;

    public CustomizeRedisCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations, long expiration) {
        super(name, prefix, redisOperations, expiration);

        Assert.hasText(name, "non-empty cache name is required");
        this.cacheMetadata = new CustomizeRedisCache.RedisCacheMetadata(name, prefix);
        this.cacheMetadata.setDefaultExpiration(expiration);
        this.redisOperations = redisOperations;
        this.cacheValueAccessor = new CustomizeRedisCache.CacheValueAccessor(redisOperations.getValueSerializer());
    }

    public <T> T get(Object key, Class<T> type) {
        ValueWrapper wrapper = this.get(key);
        return wrapper == null ? null : (T) wrapper.get();
    }

    public ValueWrapper get(Object key) {
        return this.get((new RedisCacheKey(key)).usePrefix(this.cacheMetadata.getKeyPrefix()).withKeySerializer(this.redisOperations.getKeySerializer()));
    }

   

    /**
     *  重點處理,進行重寫
     *
     * @param key
     */
    public void evict(Object key) {
        if(key instanceof  String){
            String keyString=key.toString();
            if(StringUtils.endsWith(keyString,"*")){
//                evictLikePrefix(this.cacheMetadata.cacheName + keyString);
                evictLikePrefix(keyString);
                return;
            }
            if(StringUtils.startsWith(keyString,"*")){
//                evictLikePrefix(this.cacheMetadata.cacheName + keyString);
                evictLikePrefix(keyString);
                return;
            }
        }

        // 原始
        RedisCacheElement redisCacheElement = new RedisCacheElement((new RedisCacheKey(key)).usePrefix(this.cacheMetadata.getKeyPrefix()).withKeySerializer(this.redisOperations.getKeySerializer()), (Object) null);
        this.evict(redisCacheElement);



    }


    public void evict(RedisCacheElement element) {
        Assert.notNull(element, "Element must not be null!");
        this.redisOperations.execute(new CustomizeRedisCache.RedisCacheEvictCallback(new CustomizeRedisCache.BinaryRedisCacheElement(element, this.cacheValueAccessor), this.cacheMetadata));
    }


    /**
     * 進行模糊處理 key
     *
     * @param key
     */
    public void evictLikePrefix(Object key){
        Set keys = this.redisOperations.keys(key);
        if(keys != null && keys.size() > 0){
            for(Object k : keys){
                RedisCacheElement redisCacheElement = new RedisCacheElement((new RedisCacheKey(k)).usePrefix(this.cacheMetadata.getKeyPrefix()).withKeySerializer(this.redisOperations.getKeySerializer()), (Object) null);
                this.evict(redisCacheElement);
            }
        }
    }

    public void clear() {
        this.redisOperations.execute((RedisCallback) (this.cacheMetadata.usesKeyPrefix() ? new CustomizeRedisCache.RedisCacheCleanByPrefixCallback(this.cacheMetadata) : new CustomizeRedisCache.RedisCacheCleanByKeysCallback(this.cacheMetadata)));
    }

    public String getName() {
        return this.cacheMetadata.getCacheName();
    }

    public Object getNativeCache() {
        return this.redisOperations;
    }

    private ValueWrapper toWrapper(Object value) {
        return value != null ? new SimpleValueWrapper(value) : null;
    }
}

可以關注來獲取對應的原始碼

file-list

相關文章