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。









