在java中如何使用etcd的v2 和v3 api获取配置,并且对配置的变化进行监控和监听

etcd 和zookeeper 很像,都可以用来做配置管理。并且etcd可以在目前流行的Kubernetes中使用。

但是etcd 提供了v2版本合v3的版本的两种api。我们现在分别来介绍一下这两个版本api的使用。

一、Etcd V2版本API

1、java工程中使用maven引入 etcd v2的java api操作jar包

java 复制代码
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.21.Final</version>
</dependency>
<dependency>
   <groupId>org.mousio</groupId>
   <artifactId>etcd4j</artifactId>
   <version>2.15.0</version>
</dependency>
复制代码
2、etcd的链接
java 复制代码
import mousio.etcd4j.EtcdClient;
import java.io.InputStream;
import java.net.URI;
import java.util.Properties;

public class EtcdUtil {
//etcd客户端链接
private static EtcdClient client = null;
//链接初始化
public static synchronized EtcdClient getClient(){
if (null == client){
client = new EtcdClient (URI.create(properties.getProperty("http://127.0.0.1:2379")));
}
return client;
}
}
复制代码
3、如何获取etcd的配置并且对配置进行监听 
java 复制代码
//初始化获取etcd配置并且进行配置监听
private void initEtcdConfig() {
EtcdKeysResponse dataTree ;
try {
final EtcdClient etcdClient = EtcdUtil.getClient();
//获取etcd中名称叫ETCD文件夹下的配置
EtcdKeyGetRequest etcdKeyGetRequest = etcdClient.getDir("ETCD").consistent();
dataTree = etcdKeyGetRequest.send().get();
//获取etcd的版本
System.out.println("ETCD's version:"+etcdClient.getVersion());
getConfig("/ETCD/example.config",dataTree); //加载配置项
//启动一个线程进行监听
startListenerThread(etcdClient);
} catch (Exception e) {
System.out.println("EtcdClient init cause Exception:"+e.getMessage());
e.printStackTrace();
}
}
private String getConfig(String configFile,EtcdKeysResponse dataTree){
if(null != dataTree && dataTree.getNode().getNodes().size()>0){
for(EtcdKeysResponse.EtcdNode node:dataTree.getNode().getNodes()){
if(node.getKey().equals(configFile)){
return node.getValue();
}
}
}
System.out.println("Etcd configFile"+ configFile+"is not exist,Please Check");
return null;
}
public void startListenerThread(EtcdClient etcdClient){
new Thread(()->{
startListener(etcdClient);
}).start();
}
public void startListener(EtcdClient etcdClient){
ResponsePromise promise =null;
try {
promise = etcdClient.getDir(SYSTEM_NAME).recursive().waitForChange().consistent().send();
promise.addListener(promisea -> {
System.out.println("found ETCD's config cause change");
try {
getConfig("/ETCD/example.config", etcdClient.getDir("ETCD").consistent().send().get()); //加载配置项
} catch (Exception e) {
e.printStackTrace();
System.out.println("listen etcd 's config change cause exception:{}"+e.getMessage());
}
startListener(etcdClient);
});
} catch (Exception e) {
startListener(etcdClient);
System.out.println("listen etcd 's config change cause exception:"+e.getMessage());
e.printStackTrace();
}
}
复制代码
4、使用dcmp管理 etcd的配置项
复制代码
dcmp 是一个使用go语言开发的etcd配置界面,不足的时,这个只支持v2的API,项目的地址:

GitHub - silenceper/dcmp: 基于etcd的配置管理系统 (etcd v2)

二、Etcd V3版本API

1、在工程引入如下依赖

java 复制代码
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.15.Final</version>
</dependency>
<dependency>
    <groupId>com.coreos</groupId>
    <artifactId>jetcd-core</artifactId>
    <version>0.0.2</version>
</dependency>
复制代码
2、v3 api操作工具类
java 复制代码
public class EtcdUtil {
    //etcl客户端链接
    private static Client client = null;
    //链接初始化
    public static synchronized Client getEtclClient(){
        if(null == client){
            client = Client.builder().endpoints(props.getProperty("http://127.0.0.1:2379")).build();
        }
            return client;
    }

    /**
     * 根据指定的配置名称获取对应的value
     * @param key 配置项
     * @return
     * @throws Exception
     */
    public static String getEtcdValueByKey(String key) throws Exception {
        List<KeyValue> kvs = EtcdUtil.getEtclClient().getKVClient().get(ByteSequence.fromString(key)).get().getKvs();
        if(kvs.size()>0){
            String value = kvs.get(0).getValue().toStringUtf8();
            return value;
        }
        else {
            return null;
        }
    }

    /**
     * 新增或者修改指定的配置
     * @param key
     * @param value
     * @return
     */
    public static void putEtcdValueByKey(String key,String value) throws Exception{
        EtcdUtil.getEtclClient().getKVClient().put(ByteSequence.fromString(key),ByteSequence.fromBytes(value.getBytes("utf-8")));

    }

    /**
     * 删除指定的配置
     * @param key
     * @return
     */
    public static void deleteEtcdValueByKey(String key){
         EtcdUtil.getEtclClient().getKVClient().delete(ByteSequence.fromString(key));

    }
}
//V3 api配置初始化和监听
public void init(){
try {
    //加载配置
    getConfig(EtcdUtil.getEtclClient().getKVClient().get(ByteSequence.fromString(ETCD_CONFIG_FILE_NAME)).get().getKvs());
//启动监听线程
    new Thread(() -> {
//对某一个配置进行监听
        Watch.Watcher watcher = EtcdUtil.getEtclClient().getWatchClient().watch(ByteSequence.fromString("etcd_key"));
        try {
            while(true) {
                watcher.listen().getEvents().stream().forEach(watchEvent -> {
                    KeyValue kv = watchEvent.getKeyValue();
            //获取事件变化类型
            System.out.println(watchEvent.getEventType());
                 //获取发生变化的key
                  System.out.println(kv.getKey().toStringUtf8());
          //获取变化后的value
                    String afterChangeValue = kv.getValue().toStringUtf8();

                });
            }
        } catch (InterruptedException e) {
            e.printStackTrace();

        }
    }).start();
} catch (Exception e) {
    e.printStackTrace();

}

}
private String getConfig(List<KeyValue> kvs){
    if(kvs.size()>0){
        String config = kvs.get(0).getValue().toStringUtf8();
        System.out.println("etcd 's config 's configValue is :"+config);
        return config;
    }
    else {
        return null;
    }
}

v3版本的正式版本代码(可以直接使用的工具类,并且加上了日志):

java 复制代码
import com.coreos.jetcd.Client;
import com.coreos.jetcd.Watch;
import com.coreos.jetcd.data.ByteSequence;
import com.coreos.jetcd.data.KeyValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
 *  etcd 链接和操作工具,包括启动监听 操作etcd v3 版本协议,此操作不支持v2 版本协议。
 *  v2版本的协议可以参考 https://www.cnblogs.com/laoqing/p/8967549.html
 */
public class EtcdUtil {
    public static Logger log = LoggerFactory.getLogger(EtcdUtil.class);
    //etcl客户端链接
    private static Client client = null;

    //链接初始化 单例模式
    public static synchronized Client getEtclClient(){
        if(null == client){
            client = Client.builder().endpoints("http://xxx.xxx.xxx.xxx:2379").build();
        }
        return client;
    }
    /**
     * 根据指定的配置名称获取对应的value
     * @param key 配置项
     * @return
     * @throws Exception
     */
    public static String getEtcdValueByKey(String key) throws Exception {
        List<KeyValue> kvs = EtcdUtil.getEtclClient().getKVClient().get(ByteSequence.fromString(key)).get().getKvs();
        if(kvs.size()>0){
            String value = kvs.get(0).getValue().toStringUtf8();
            return value;
        }
        else {
            return null;
        }
    }
    /**
     * 新增或者修改指定的配置
     * @param key
     * @param value
     * @return
     */
    public static void putEtcdValueByKey(String key,String value) throws Exception{
        EtcdUtil.getEtclClient().getKVClient().put(ByteSequence.fromString(key),ByteSequence.fromBytes(value.getBytes("utf-8")));
    }
    /**
     * 删除指定的配置
     * @param key
     * @return
     */
    public static void deleteEtcdValueByKey(String key){
        EtcdUtil.getEtclClient().getKVClient().delete(ByteSequence.fromString(key));
    }
    /**
     * etcd的监听,监听指定的key,当key 发生变化后,监听自动感知到变化。
     * @param key 指定需要监听的key
     */
    public static void initListen(String key){
        try {
            //加载配置
            getConfig(EtcdUtil.getEtclClient().getKVClient().get(ByteSequence.fromString(key)).get().getKvs());
            new Thread(() -> {
                Watch.Watcher watcher = EtcdUtil.getEtclClient().getWatchClient().watch(ByteSequence.fromString(key));
                try {
                    while(true) {
                        watcher.listen().getEvents().stream().forEach(watchEvent -> {
                            KeyValue kv = watchEvent.getKeyValue();
                            log.info("etcd event:{} ,change key is:{},afterChangeValue:{}",watchEvent.getEventType(),kv.getKey().toStringUtf8(),kv.getValue().toStringUtf8());
                        });
                    }
                } catch (InterruptedException e) {
                    log.info("etcd listen start cause Exception:{}",e);
                }
            }).start();
        } catch (Exception e) {
            log.info("etcd listen start cause Exception:{}",e);
        }
    }
    private static String getConfig(List<KeyValue> kvs){
        if(kvs.size()>0){
            String config = kvs.get(0).getKey().toStringUtf8();
            String value = kvs.get(0).getValue().toStringUtf8();
            log.info("etcd 's config 's config key is :{},value is:{}",config,value);
            return value;
        }
        else {
            return null;
        }
    }
}

运行后的效果:

另外v3 版本api 的管理界面,可以参考如下开源项目

GitHub - shiguanghuxian/etcd-manage: 一个现代的etcd v3管理ui

本人github源码:

bigdata_tools/yongqing-bigdata-tools/yongqing-etcd-tool at master · 597365581/bigdata_tools · GitHub

bigdata_tools/yongqing-bigdata-tools/yongqing-etcd-tool-v2 at master · 597365581/bigdata_tools · GitHub

相关推荐
考虑考虑6 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261356 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊7 小时前
Java学习第22天 - 云原生与容器化
java
渣哥9 小时前
原来 Java 里线程安全集合有这么多种
java
间彧9 小时前
Spring Boot集成Spring Security完整指南
java
间彧10 小时前
Spring Secutiy基本原理及工作流程
java
Java水解11 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆13 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学13 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole13 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端