1. zookper 的安装
2. zk_ui 的安装
zkui-2.0-SNAPSHOT-jar-with-dependencies.jar 下载文件,修改配置文件。
主要修改如下:zkServer 的地址
#Server Port
serverPort=9090
#Comma seperated list of all the zookeeper servers
zkServer=172.16.0.4:2181
#Specific roles for ldap authenticated users. Ignore if using file based authentication.
ldapRoleSet={"users": [{ "username":"domain\\user1" , "role": "ADMIN" }]}
userSet = {"users": [{ "username":"admin" , "password":"manager","role": "ADMIN" },{ "username":"appconfig" , "password":"appconfig","role": "USER" }]}
#Set to prod in production and dev in local. Setting to dev will clear history each time.
3. java 代码编写
3.1 mavn 包 引用
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.1.0</version>
</dependency>
3.2 在zookper 创建node 节点
3.3 zookper 文件节点读取
pring boot项目的配置文件都是配置在classpath环境变量下面,系统会默认使用ConfigFileApplicationListener去加载;但是如果项目打成war、jar包并且已经升级过了或者在项目之外有自定义的配置文件,这时候想改配置
文件这时候就需要重新打包了,这样很麻烦,而Spring boot也给我们提供了扩展的接口EnvironmentPostProcessor;
如下是实现从 zookeper 中读取配置文件实现,在加载 配置文件时,需要添加配置文件。
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.RetryOneTime;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZookeeperEnvironmentPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
try {
System.out.println("获取ev对象,初始化配置");
String configCenterUrl = environment.getProperty("config.zookeeper.url");
String configNodename = environment.getProperty("config.zookeeper.nodename");
CuratorFramework zkClient = CuratorFrameworkFactory.newClient(configCenterUrl,new RetryOneTime(1000));
zkClient.start();
// 1. TODO 获取节点下的字节点,下面的每一个子节点都代表一项配置。
List<String> strings = null;
Map<String, Object> configMap = new HashMap<>();
List<String> configNames = zkClient.getChildren().forPath("/"+configNodename);
for (String configName:configNames) {
byte[] value = zkClient.getData().forPath("/"+configNodename+"/"+configName);
configMap.put(configName,new String(value));
System.out.println(configName+":"+ new String(value));
}
// 2 TODO 放到 spring 容器里面
MapPropertySource propertySource = new MapPropertySource("zkPropertySource",configMap);
environment.getPropertySources().addFirst(propertySource);
// 3 TODO 如何动态获取zookper 配置
TreeCache treeCache = new TreeCache(zkClient,"/"+configNodename);
treeCache.start();
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
switch(treeCacheEvent.getType()){
case NODE_UPDATED:
System.out.println("收到了数据变化通知"+treeCacheEvent.getData());
String configName = treeCacheEvent.getData().getPath().replace("/"+configNodename+"/","");
String newValue = new String(treeCacheEvent.getData().getData());
// TODO spring 已经创建对象, @value 注入的值如何改变
break;
default:
break;
}
}
});
}catch (Exception ex){
ex.printStackTrace();
}
}
}
3.4 在META-INF下创建spring.factories,并且引入 ZookeeperEnvironmentPostProcessor 类
# 告诉 srping boot ,初始化的时候加载我们的自定义拓展
org.springframework.boot.env.EnvironmentPostProcessor=com.hou.zk.demo.config.ZookeeperEnvironmentPostProcessor
3.5 配置项更改通知修改
// 3 TODO 如何动态获取zookper 配置
TreeCache treeCache = new TreeCache(zkClient,"/"+configNodename);
treeCache.start();
treeCache.getListenable().addListener(new TreeCacheListener() {
@Override
public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {
switch(treeCacheEvent.getType()){
case NODE_UPDATED:
System.out.println("收到了数据变化通知"+treeCacheEvent.getData());
String configName = treeCacheEvent.getData().getPath().replace("/"+configNodename+"/","");
String newValue = new String(treeCacheEvent.getData().getData());
// TODO spring 已经创建对象, @value 注入的值如何改变
break;
default:
break;
}
}
});
总结说明:
代码中虽然实现了配置文件的读取,能够实现在不修改原来代码修改的情况下,实现本地配置文件切换到zookper的分布式配置,但是动态的配置文件的同步还是没有好的方法实现。