0
点赞
收藏
分享

微信扫一扫

工具类ConfigTool封装Nacos Config 本地缓存

Nacos Config的SpringBoot api使用起来不太灵活, 我们更希望要的是一个抽象的缓存工具,Nacos Config只是其中一种实现。
Nacos Config的java api并不提供本地缓存,每次请求都会去配置中心拉取数据,所以需要我们动手封装一下。

定义配置工具接口

import java.util.Map;
import java.util.Properties;

public interface IConfig {

    String getStringConfig(String path);

    Object getJsonConfig(String path, String key);

    Map<String, Object> getJsonConfig(String path);

    Properties getPropertiesConfig(String path);

}

Nacos Config 实现

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.qiejk.commons.util.base.JsonTool;
import com.qiejk.commons.util.base.LogTool;
import com.qiejk.commons.util.base.SpringContextTool;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;

@Component
public class NacosConfigTool implements IConfig {

    private static final String GROUP = "COMMON_CONFIG";

    private ConfigService service;

    // 本地缓存
    private Map<String, String> cache = new ConcurrentHashMap<>();

    private Map<String, Object> lockMap = new ConcurrentHashMap<>();

    public NacosConfigTool() {
        try {
            service = NacosFactory.createConfigService(SpringContextTool.getBean(ConfigConfiguration.class).getNacosServerAddr());
        } catch (NacosException e) {
            LogTool.error("NacosConfigTool init error.", e);
        }

    }

    private String getConfig(String dataId) {
        String ret;
        if ((ret = cache.get(dataId)) != null) {
            return ret;
        }

        // Nocos 的 addLisener 竟然有线程安全问题,其实是同一个节点可以add多个lisener  这里需要做一个锁定
        Object lock = lockMap.computeIfAbsent(dataId, k -> new Object());

        synchronized (lock) {
            if ((ret = cache.get(dataId)) == null) {
                ret = getConfigFromRemote(dataId);
                if (ret != null) {
                    cache.put(dataId, ret);
                }
            }
            lockMap.remove(dataId);
        }

        return ret;
    }

    private String getConfigFromRemote(String dataId) {
        try {
            return service.getConfigAndSignListener(dataId, GROUP, 5000, new MNacosConfigListener(dataId, cache));
        } catch (NacosException e) {
            LogTool.error("NacosConfigTool getConfigFromRemote error. dataId=" + dataId, e);
        }

        return null;
    }

    // 配置监听
    static class MNacosConfigListener implements Listener {

        private String dataId;
        private Map<String, String> cache;

        public MNacosConfigListener(String dataId, Map<String, String> cache) {
            this.dataId = dataId;
            this.cache = cache;
        }

        @Override
        public Executor getExecutor() {
            return null;
        }

        @Override
        public void receiveConfigInfo(String configInfo) {
            cache.put(dataId, configInfo);
            System.out.println("MNacosConfigListener.receiveConfigInfo " + dataId + " refresh config. " + configInfo);
        }
    }


    @Override
    public String getStringConfig(String dataId) {
        return getConfig(dataId);
    }

    @Override
    public Object getJsonConfig(String dataId, String key) {
        return getJsonConfig(dataId).get(key);
    }

    @Override
    public Map<String, Object> getJsonConfig(String dataId) {
        return JsonTool.json2Map(getConfig(dataId));
    }

    @Override
    public Properties getPropertiesConfig(String dataId) {
        return null;
    }

工具类


import com.qiejk.commons.util.base.u.IConfig;

import java.util.Map;
import java.util.Properties;

public class ConfigTool {

    private static IConfig config = SpringContextTool.getBean(IConfig.class);

    private ConfigTool() {
    }

    public static Object getJsonConfig(String path, String key) {
        return config.getJsonConfig(path, key);
    }

    public static Map<String, Object> getJsonConfig(String path) {
        return config.getJsonConfig(path);
    }

    public static Properties getPropertiesConfig(String path) {
        return config.getPropertiesConfig(path);
    }

    public static String getStringConfig(String path){
        return config.getStringConfig(path);
    }

}

这样我们就得到了一个不知道底层是啥实现的配置工具,并且默认实现是Nacos Config,并且默认有本地缓存。

效果

    @Test
    public void testNacosConfig(){
        while(true){
            Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS);

            System.out.println("test = " + ConfigTool.getStringConfig("test"));

        }
    }
test = 5
MNacosConfigListener.receiveConfigInfo test refresh config. 6
test = 6
test = 6
MNacosConfigListener.receiveConfigInfo test refresh config. 7
test = 7
test = 7

优化

其实还还有很大优化空间,比如本地缓存换成guava。

举报

相关推荐

0 条评论