consul中的yml配置持久化到MongoDB

設計思路:

1.   獲取到consul中的配置文件內容;

經過consul的官網查看consul對外提供的RESTAPI,找到獲取consul中全部配置文件的名稱接口;找到根據配置文件名稱獲取配置文件內容的接口;html

2.   保存到數據庫中;

經過mongoTemplate操做MongoDB數據庫;每次配置文件修改後保存的時候在mongo表裏新增一條數據;spring

3.   保存以前判斷當前版本和數據庫版本是否一致;

mongo數據庫裏存儲當前版本的hash值,若是新版本的hash值和當前版本的hash值一致就放棄本次保存操做,視爲配置沒有改動,保留原來版本;數據庫

4.   保留20個版本;

新版本插入以前獲取當前版本編號,若是當前沒有版本則插入到第一個版本;若是當前有版本和當前版本號小於20則插入到當前最大版本+1的版本;若是當前版本=20在則刪除第1個版本,以後每一個版本遞減1,新版本插入到第20版本;app

5consul配置:

consul可視化界面修改配置後點擊保存時調用本身的rest接口ide

 
        {
            "watches":[
                {
                    "type":"keyprefix",
                    "prefix":"config/",
                    "token":"p2BE1AtpwPbrxZdC6k+eXA",
                    "handler_type":"http",
                    "http_handler_config":{
                        "path":" http://127.0.0.1/consul/config/"
                    }
                }
            ]
        }

廢話很少說,先上代碼url

1.   調用 consul提供的RESTAPI接口的讀取配置;

2.   @Autowired
private RestTemplate restTemplate;

@Override
public String readConsul(String url, String ymlName, String token) {
    try {
        String reqJsonStr;
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("text/html; charset=UTF-8");
        headers.setContentType(type);
        headers.set("X-Consul-Token", token);
        HttpEntity<String> entity = new HttpEntity<String>(headers);
        ResponseEntity<String> exchange = restTemplate.exchange(new URI(url + ymlName), HttpMethod.GET, entity, String.class);
        String result = exchange.getBody();
        List<RestGetResultDo> conList = JSON.parseArray(result, RestGetResultDo.class);
        return conList.get(0).getValue();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

3.   獲取consul中全部yml名稱接口

4.   @Override
public List<String> getConsulConfigYmlNameList(String url, String token) {
    RestTemplate restTemplate2 = new RestTemplate();
    try {
        String reqJsonStr;
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("text/html; charset=UTF-8");
        headers.setContentType(type);
        headers.set("X-Consul-Token", token);
        HttpEntity<String> entity = new HttpEntity<String>(headers);
        ResponseEntity<String> exchange = restTemplate.exchange(new URI(url), HttpMethod.GET, entity, String.class);
        String result = exchange.getBody();
        result = result.replaceAll("\r|\n| |\\[|\\]|\\\"", "");
        String[] split = result.split(",");
        return Arrays.asList(split);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

3.consul同步到mongoDB接口

public static final String VERSION_NUMBER = "versionNumber";
public static final int MAX_VERSION = 20;
@Autowired
private ConsulConfigManage consulConfigManage;

@Autowired
private MongoTemplate mongoTemplate;

@Autowired
private ConsulProperties consulProperties;


@Value("${spring.cloud.consul.token}")
private String consulToken;


/**
 * consul
配置持久化到MongoDB的實現類
 *
 * @return
 
*/
@Override
public Boolean consulToMongoDB() {
    int versionNumber = 1;
    int oldFirstDocumentHash = 1;
    int newDocumentHash = 1;
    boolean isSync = false;
    try {
        ConsulConfigDo configDo = new ConsulConfigDo();
        //獲取到全部配置文件的名稱
       
List<String> consulConfigYmlNameList = consulConfigManage.getConsulConfigYmlNameList("http://" + consulProperties.getHost() + ":" + consulProperties.getPort() + "/v1/kv/" + "?keys", consulToken);
        //把每一個配置文件的name和content放到map中
       
Map map = new HashMap();
        for (String ymlName : consulConfigYmlNameList) {
            String ymlContent = consulConfigManage.readConsul("http://" + consulProperties.getHost() + ":" + consulProperties.getPort() + "/v1/kv/", ymlName, consulToken);
            ymlName = ymlName.contains(".") ? ymlName = ymlName.substring(0, ymlName.indexOf(".")) : ymlName;
            map.put(ymlName, ymlContent);
        }
        //查詢MongoDB中最近添加的一個版本
       
List<ConsulConfigDo> consulConfigDos = mongoTemplate.find(new Query().with(new Sort(new Sort.Order(Sort.Direction.DESC, "_id"))), ConsulConfigDo.class);
        ConsulConfigDo first = null;
        //初始版本
       
if (consulConfigDos.size() == 0) {
            configDo.set_id(System.currentTimeMillis());
            configDo.setConsul_content(map);
            configDo.setVersionNumber(String.format("%02d", versionNumber));
            configDo.setHash(hash(configDo.getConsul_content()));
            mongoTemplate.insert(configDo);
            isSync = true;
        } else {
            first = consulConfigDos.get(0);
            //最近添加的一個版本hash
           
oldFirstDocumentHash = first.getHash();
            configDo.setConsul_content(map);
            newDocumentHash = hash(configDo.getConsul_content());
            if (newDocumentHash == oldFirstDocumentHash) {
                //不一樣步
               
return isSync;
            } else {
                //同步
               
String versionNumber1 = first.getVersionNumber();
                Integer integer = Integer.valueOf(versionNumber1);
                //若是數據小於20
               
if (integer < MAX_VERSION) {
                    versionNumber = integer + 1;
                } else {
                    //刪掉第一條數據
                   
mongoTemplate.remove(new Query(Criteria.where(VERSION_NUMBER).is("01")), ConsulConfigDo.class);
                    //每條數據的versionNumber遞減1
                   
List<ConsulConfigDo> documents = mongoTemplate.find(new Query().with(new Sort(new Sort.Order(Sort.Direction.ASC, "_id"))), ConsulConfigDo.class);
                    for (ConsulConfigDo document : documents) {
                        Integer versionNum = Integer.valueOf(document.getVersionNumber());
                        String format = String.format("%02d", versionNum -= 1);
                        mongoTemplate.updateFirst(new Query(Criteria.where(VERSION_NUMBER).is(document.getVersionNumber())), Update.update(VERSION_NUMBER, format), ConsulConfigDo.class);
                    }
                    versionNumber = 20;
                }
                //插入到第20個版本
               
configDo.setVersionNumber(String.format("%02d", versionNumber));
                configDo.setHash(hash(configDo.getConsul_content()));
                configDo.set_id(System.currentTimeMillis());
                mongoTemplate.insert(configDo);
                isSync = true;
            }
        }
        return isSync;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 *
計算hash值
 *
 * @param
key
 
* @return
 
*/
private int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

4.consul返回結構類

@Data
public class RestGetResultDo implements Serializable {
    private int LockIndex;
    private String Key;
    private int Flags;
    private String Value;
    private int CreateIndex;
    private int ModifyIndex;


}

5.MongoDB結構

@Validated
@Data
@ToString
@Document(collection = "app_yml_config")
public class ConsulConfigDo {

    private Long _id;
    private Map consul_content;
    private String versionNumber;
    private int hash; }
相關文章
相關標籤/搜索