All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ideaaedi.extspringcache.redis.ExtRedisCache Maven / Gradle / Ivy

The newest version!
package com.ideaaedi.extspringcache.redis;


import com.ideaaedi.extspringcache.annotation.ExtCacheableOop;
import com.ideaaedi.extspringcache.annotation.RedisOop;
import com.ideaaedi.extspringcache.enums.RedisExpireStrategyEnum;
import com.ideaaedi.extspringcache.support.ExtCacheHelper;
import com.ideaaedi.extspringcache.support.SafeContainer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.time.Duration;
import java.util.Map;

/**
 * 拓展RedisCache
 *
 * @author JustryDeng
 * @since 2020/11/4 21:33:03
 */
@Slf4j
public class ExtRedisCache extends RedisCache {
    
    private final String name;
    
    private final RedisCacheWriter cacheWriter;
    
    private final RedisCacheConfiguration cacheConfig;
    
    private final  Map cacheConfigMap;
    
    /**
     * Create new {@link ExtRedisCache}.
     *
     * @param name
     *         must not be {@literal null}.
     * @param cacheWriter
     *         must not be {@literal null}.
     * @param cacheConfig
     *         must not be {@literal null}.
     * @param cacheConfigMap
     *         must not be {@literal null}.
     */
    protected ExtRedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig,
                            Map cacheConfigMap) {
        super(name, cacheWriter, cacheConfig);
        this.name = name;
        this.cacheWriter = cacheWriter;
        this.cacheConfig = cacheConfig;
        this.cacheConfigMap = cacheConfigMap;
    }
    
    @Override
    @Nullable
    public ValueWrapper get(@NonNull Object key) {
        Boolean refreshCurrCache = SafeContainer.THREAD_LOCAL_REFRESH_CURR_CACHE.get();
        if (BooleanUtils.isTrue(refreshCurrCache)) {
            // 这里返回null, 那么程序就会走方法里面的逻辑, 走完后再把结果放入缓存, 继而:变相实现了刷新当前key的缓存
            log.info(" refresh curr key [{}]'s cache-value", key);
            return null;
        }
        ValueWrapper valueWrapper = super.get(key);
        if (valueWrapper != null) {
            log.info(" hit redis-cache, curr name is [{}], curr key is [{}]", this.name, key);
        }
        return valueWrapper;
    }
    
    @Override
    public void put(@NonNull Object key, @Nullable Object value) {
        Object cacheValue = preProcessCacheValue(value);
        if(!isAllowNullValues() && cacheValue == null) {
            return;
        }
        Duration ttl = cacheConfig.getTtl();
        Duration overrideTtl = overrideTtlIfNecessary(name);
        if (overrideTtl != null) {
            ttl = overrideTtl;
        }
        //noinspection ConstantConditions
        cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), ttl);
    }
    
    @Override
    public ValueWrapper putIfAbsent(@NonNull Object key, Object value) {
        Object cacheValue = preProcessCacheValue(value);
        if(!isAllowNullValues() && cacheValue == null) {
            return null;
        }
        Duration ttl = cacheConfig.getTtl();
        Duration overrideTtl = overrideTtlIfNecessary(name);
        if (overrideTtl != null) {
            ttl = overrideTtl;
        }
        //noinspection ConstantConditions
        byte[] result = cacheWriter.putIfAbsent(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), ttl);
        if (result == null) {
            return null;
        }
        return new SimpleValueWrapper(fromStoreValue(deserializeCacheValue(result)));
    }
    
    /**
     * 是否使用自定义的ttl。 若不使用,则返回null, 若使用,则返回要使用的ttl
     *
     * @param cacheName
     *            缓存的命名空间
     * @return null-不使用自定义的ttl; 否者使用自定义的ttl
     */
    private Duration overrideTtlIfNecessary(String cacheName) {
        ExtCacheableOop extCacheableOop = ExtCacheHelper.determineExtCacheOop(cacheName);
        if (extCacheableOop == null) {
            return null;
        }
        RedisOop redis = extCacheableOop.getRedis();
        RedisExpireStrategyEnum strategy = redis.getExpireStrategy();
        Duration customTtl = Duration.of(redis.getExpireTime(), redis.getTimeUnit());
        if (strategy == RedisExpireStrategyEnum.CUSTOM) {
            return customTtl;
        }
        RedisCacheConfiguration propertiesConfig = cacheConfigMap.get(cacheName);
        if (propertiesConfig == null) {
            return customTtl;
        }
        Duration ttl = propertiesConfig.getTtl();
        //noinspection ConstantConditions 配置的过期时间必须大于0才会生效
        if (ttl == null || ttl.isNegative() || ttl.isZero()) {
            return customTtl;
        }
        // 返回null, 那么(上层逻辑会判断,并)会走配置文件中配置的Duration
        return null;
    }
    
    /**
     * see super#createAndConvertCacheKey
     */
    private byte[] createAndConvertCacheKey(Object key) {
        return serializeCacheKey(createCacheKey(key));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy