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

org.zodiac.cache.service.DynamicMemoryCacheService Maven / Gradle / Ivy

The newest version!
package org.zodiac.cache.service;

import org.springframework.cache.Cache;
import org.springframework.cache.concurrent.ConcurrentMapCache;
import org.zodiac.commons.util.Colls;
import org.zodiac.commons.util.ObjectUtil;
import org.zodiac.sdk.toolkit.util.SystemClock;
import org.zodiac.sdk.toolkit.util.lang.StrUtil;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class DynamicMemoryCacheService extends BaseMemoryCacheService implements BaseCacheService {

    /**
     * cache的清理时间缓存。
     */
    private final ConcurrentHashMap CACHE_CLEANDATE_CACHE = new ConcurrentHashMap<>();

    /**
     * cache的过期时间缓存。
     */
    private final ConcurrentHashMap CACHE_EXPIREDMINUTES_CACHE = new ConcurrentHashMap<>();

    /**
     * cache的时间戳缓存。
     */
    private final ConcurrentHashMap> CACHE_TIMESTAMP_CACHE = new ConcurrentHashMap<>();

    public DynamicMemoryCacheService(){
        super.afterPropertiesSet();
    }

    /**
     * 指定cacheNames,无过期时间。
     * @param cacheNames 缓存名称列表
     */
    public DynamicMemoryCacheService(String... cacheNames){
        List caches = new ArrayList<>(cacheNames.length);
        for(String cacheName : cacheNames){
            caches.add(new ConcurrentMapCache(cacheName));
        }
        setCaches(caches);
        super.afterPropertiesSet();
    }

    /**
     * 指定cacheNames,统一过期时间。
     * @param expiredMinutes 过期分钟数
     * @param cacheNames 缓存名称列表
     */
    public DynamicMemoryCacheService(int expiredMinutes, String... cacheNames){
        List caches = new ArrayList<>(cacheNames.length);
        for(String cacheName : cacheNames){
            caches.add(new ConcurrentMapCache(cacheName));
            this.CACHE_EXPIREDMINUTES_CACHE.put(cacheName, expiredMinutes);
            this.CACHE_CLEANDATE_CACHE.put(cacheName, "");
        }
        setCaches(caches);
        super.afterPropertiesSet();
    }

    /**
     * 指定cacheNames,附带不同的过期时间。
     * @param cacheName2ExpiredMinutes 缓存名称和过期分钟数的Key-Value对
     */
    public DynamicMemoryCacheService(Map cacheName2ExpiredMinutes){
        List caches = new ArrayList<>(cacheName2ExpiredMinutes.size());
        for(Map.Entry cacheEntry : cacheName2ExpiredMinutes.entrySet()){
            caches.add(new ConcurrentMapCache(cacheEntry.getKey()));
            this.CACHE_EXPIREDMINUTES_CACHE.put(cacheEntry.getKey(), cacheEntry.getValue());
            this.CACHE_CLEANDATE_CACHE.put(cacheEntry.getKey(), "");
        }
        setCaches(caches);
        super.afterPropertiesSet();
    }

    public  T getCacheObj(String cacheName, Object objKey, Class tClass) {
        Cache cache = getCache(cacheName);
        if(cache == null){
            return null;
        }
        /*已过期,则清空缓存返回null。*/
        if(isExpired(cacheName, objKey)){
            cache.evict(objKey);
            if(log.isDebugEnabled()){
                log.debug("{} cache expired and cleaned from {} .", objKey, cacheName);
            }
            return null;
        }
        return cache.get(objKey, tClass);
    }

    public void putCacheObj(String cacheName, Object objKey, Object obj) {
        super.putCacheObj(cacheName, objKey, obj);
        refreshCacheTimestamp(cacheName, objKey);
        clearOutOfDateDataIfNeeded(cacheName);
    }

    @Override
    public synchronized void clearOutOfDateData(String cacheName) {
        Cache cache = getCache(cacheName);
        ConcurrentMap cacheMap = (ConcurrentMap)cache.getNativeCache();
        if(ObjectUtil.isEmpty(cacheMap)){
            log.debug("No cached data temporarily from {} .", cacheName);
            return;
        }
        int count = 0;
        for(Map.Entry entry : cacheMap.entrySet()){
            /*已过期,则清空缓存返回null。*/
            if(isExpired(cacheName, entry.getKey())){
                cache.evict(entry.getKey());
                count++;
                log.debug("Clean up expired cache data {} from {} .", entry.getKey(), cacheName);
            }
        }
        log.debug("Cleanup completed expired cache data {} in total from {} .", count, cacheName);
    }

    public boolean isExpired(String cacheName, Object objKey) {
        ConcurrentMap timestampCache = CACHE_TIMESTAMP_CACHE.get(cacheName);
        if(Colls.isEmpty(timestampCache)){
            return false;
        }
        Long cacheTimestamp = timestampCache.get(objKey);
        if(cacheTimestamp == null){
            return false;
        }
        long currentTimestamp = SystemClock.nowTimeMillis();
        int expiredMinutes = CACHE_EXPIREDMINUTES_CACHE.get(cacheName);
        return (currentTimestamp - cacheTimestamp) > (expiredMinutes*60000);
    }

    private void clearOutOfDateDataIfNeeded(String cacheName){
        boolean needed = true;
        String today = LocalDate.now().toString();
        if(CACHE_CLEANDATE_CACHE.containsKey(cacheName)){
            needed = StrUtil.notEqualsCharSeq(today, CACHE_CLEANDATE_CACHE.get(cacheName));
        }
        if(needed){
            log.debug("New execution cycle cleans up expired local cache from {} .", cacheName);
            clearOutOfDateData(cacheName);
            CACHE_CLEANDATE_CACHE.put(cacheName, today);
        }
    }

    /*
     * 刷新缓存时间戳。
     */
    private void refreshCacheTimestamp(String cacheName, Object objKey) {
        ConcurrentHashMap timestampCache = CACHE_TIMESTAMP_CACHE.get(cacheName);
        if(timestampCache == null){
            timestampCache = new ConcurrentHashMap<>();
            CACHE_TIMESTAMP_CACHE.put(cacheName, timestampCache);
        }
        timestampCache.put(objKey, SystemClock.nowTimeMillis());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy