consul中的yml配置持久化到MongoDB

设计思路:

1.   获取到consul中的配置文件内容;

通过consul的官网查看consul对外提供的RESTAPI,找到获取consul中所有配置文件的名称接口;找到根据配置文件名称获取配置文件内容的接口;

2.   保存到数据库中;

通过mongoTemplate操作MongoDB数据库;每次配置文件修改后保存的时候在mongo表里新增一条数据;

3.   保存之前判断当前版本和数据库版本是否一致;

mongo数据库里存储当前版本的hash值,如果新版本的hash值和当前版本的hash值一致就放弃本次保存操作,视为配置没有改动,保留原来版本;

4.   保留20个版本;

新版本插入之前获取当前版本编号,如果当前没有版本则插入到第一个版本;如果当前有版本和当前版本号小于20则插入到当前最大版本+1的版本;如果当前版本=20在则删除第1个版本,之后每个版本递减1,新版本插入到第20版本;

5consul配置:

consul可视化界面修改配置后点击保存时调用自己的rest接口

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

废话不多说,先上代码

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;
}

 

posted @ 2019-08-01 18:53  不会飞的机器猫  阅读(1664)  评论(0编辑  收藏  举报