springmvc redis @Cacheable扩展(一)

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

posted @ 2021-03-09 09:58  要吃西蓝花  阅读(360)  评论(0编辑  收藏  举报