緩存機制

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import net.blogjava.frankiegao123.log.slf4j.Log;
import net.blogjava.frankiegao123.log.slf4j.LogFactory;

/**
 * <p>System.Config 配置緩存</p>
 *
 * @author frankiegao123
 * 2010-6-10 下午02:48:35
 */
@Component("configCache")
public class ConfigCache implements ConfigService {

    private final static Log log = LogFactory.getLog(ConfigCache.class);

    /**
     * 更新緩存時記錄的時間
     */
    private volatile long time = 0L;

    /**
     * 正在更新緩存時的門閂,爲 true 時表示當前沒有更新緩存,爲 true 時表示當前正在更新緩存
     */
    private volatile boolean updateGate = true;

    /**
     * 緩存容器
     */
    private Map<String, SysConfig> cache = new ConcurrentHashMap<String, SysConfig>();

    private CommonDao commonDao;

    @Autowired
    public ConfigCache(CommonDao commonDao) {
        this.commonDao = commonDao;
        log.info("initializing cache...");
        refreshCache();
        time = System.currentTimeMillis();
        log.info("initialized cache finished, cache size: {}, set cache time to current: {}, cache timeout: {}ms", cache.size(), time, ConfigConstant.CACHE_TIMEOUT);
    }

    /**
     * <p>根據配置的鍵名獲取配置值</p>
     *
     * @param configKey
     * @return
     * @author frankiegao123
     * 2010-6-10 上午11:18:33
     */
    public SysConfig getSysConfig(String configKey) {
        long current = System.currentTimeMillis();
        if(updateGate && isTimeout(current)) {
            synchronized (this) {
                if(updateGate) {
                    timeoutSynRefresh(current);
                }
            }
        }
        return cache.get(configKey);
    }

    /**
     * <p>超時時更新緩存。該方法需要在同步環境中調用</p>
     * @param current
     * @author frankiegao123
     * 2010-6-10 上午11:16:30
     */
    private void timeoutSynRefresh(long current) {
        updateGate = false;
        log.info("refresh cache start..., time out: {}, size: {}, set updateGate to false", (current - time) / 1000.0, cache.size());
        try {
            refreshCache();
            time = current;
            log.info("refresh cache finished, size after update: {}, set cache time to current: {}", cache.size(), String.valueOf(time));
        } catch (Exception e) {
            log.error("refresh cache failed", e);
        } finally {
            updateGate = true;
            log.info("refresh cache finished, set updateGate to true");
        }
    }

    /**
     * <p>更新緩存數據</p>
     *
     * @author frankiegao123
     * 2010-6-10 上午11:15:55
     */
    private void refreshCache() {
        List<SysConfig> configs = commonDao.getSysConfigs();
        for(Iterator<SysConfig> i = configs.iterator(); i.hasNext(); ) {
            SysConfig config = i.next();
            cache.put(config.getKey(), config);
        }
        commonDao.clear();
        SysConfig config = cache.get(SysConfig.TEST_KEY);
        if(config == null) {
            log.error("refresh cache, cannot find TEST_KEY");
        } else {
            log.info("refresh cache, find TEST_KEY = [{}]", config.getValue());
        }
    }

    /**
     * <p>緩存是否超時</p>
     *
     * @param current
     * @return
     * @author frankiegao123
     * 2010-6-10 上午11:16:12
     */
    private boolean isTimeout(long current) {
        return (current - time >= ConfigConstant.CACHE_TIMEOUT);
    }

    Collection<SysConfig> getSysConfigs() {
        return Collections.unmodifiableCollection(cache.values());
    }

    int getSize() {
        return cache.size();
    }

    long getTime() {
        return time;
    }

    boolean isUpdateGate() {
        return updateGate;
    }

    void refresh() {
        time = 0L;
        log.info("refresh: reset cache time to 0");
        getSysConfig("none");
        log.info("refresh: refresh cache finished, cache: {0}", String.valueOf(time));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章