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 等参数,那么,点进去看源码,就会发现
CustomizedRedisCacheManager 和 CustomizeRedisCache ,和 高版本的名字很像,那么仔细看看,发现 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  要吃西蓝花  阅读(419)  评论(0)    收藏  举报