0、市面上的配置中心产品
说到配置中心,大家应该也了解目前市面上用的较多的配置中心:
百度的Disconf、Spring Cloud Config、携程的Apollo、阿里的Nacos等。
由于Disconf不再维护,以下对Spring Cloud Config、Apollo、Nacos的功能点做的对比
大家平时在开发时,项目中会用到很多配置,有些配置还和环境有关,开发、测试和生产的配置也不一样;
或者在做某一个功能时,上线后配置有可能更改,即使我们将变量写在配置中,但还是需要重新发布服务,
所以,如果有个配置中心,当更新某个配置时,可以实时生效,岂不快哉!
如果做一个分布式配置中心的产品,所需要实现的功能很多,如配置存储、配置实时推送、权限校验、版本管理&回滚、配置格式校验等。
本文介绍使用Springboot2.x+Zookeeper实现简易的分布式配置中心,使用Zookeeper存储配置,本地缓存配置,监听zookeeper的配置更新,本地实时更新。
1、引入依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> </parent>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <zk.curator.version>2.12.0</zk.curator.version> </properties>
<dependencies>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>${zk.curator.version}</version> </dependency>
</dependencies>
|
2、配置中心类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| @Component public class PropertiesCenter {
Properties properties = new Properties(); CuratorFramework client = null; TreeCache treeCache = null; @Value("${zookeeper.url}") private String zkUrl; private final String CONFIG_NAME = "/config-center"; public PropertiesCenter() { } private void init() { RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3); client = CuratorFrameworkFactory.newClient(zkUrl, retryPolicy); treeCache = new TreeCache(client, CONFIG_NAME); }
public void setProperties(String key, String value) throws Exception { String propertiesKey = CONFIG_NAME + "/" + key; Stat stat = client.checkExists().forPath(propertiesKey); if(stat == null) { client.create().forPath(propertiesKey); } client.setData().forPath(propertiesKey, value.getBytes()); }
public String getProperties(String key) { return properties.getProperty(key); } @PostConstruct public void loadProperties() { try { init(); client.start(); treeCache.start(); Stat stat = client.checkExists().forPath(CONFIG_NAME); if(stat == null) { client.create().forPath(CONFIG_NAME); } List<String> configList = client.getChildren().forPath(CONFIG_NAME); for (String configName : configList) { byte[] value = client.getData().forPath(CONFIG_NAME + "/" + configName); properties.setProperty(configName, new String(value)); } treeCache.getListenable().addListener(new TreeCacheListener() { @Override public void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception { if (Objects.equals(treeCacheEvent.getType(), TreeCacheEvent.Type.NODE_ADDED) || Objects.equals(treeCacheEvent.getType(), TreeCacheEvent.Type.NODE_UPDATED)) { String updateKey = treeCacheEvent.getData().getPath().replace(CONFIG_NAME + "/", ""); properties.setProperty(updateKey, new String(treeCacheEvent.getData().getData())); System.out.println("数据更新: "+treeCacheEvent.getType()+", key:"+updateKey+",value:"+new String(treeCacheEvent.getData().getData())); } } }); } catch (Exception e) { e.printStackTrace(); } } }
|
3、测试的set/get接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @RestController public class PropertiesController { @Autowired PropertiesCenter propertiesCenter; @GetMapping("get/{key}") public String getProperties(@PathVariable String key) { return propertiesCenter.getProperties(key); } @GetMapping("set/{key}/{value}") public String setProperties(@PathVariable String key, @PathVariable String value) throws Exception { propertiesCenter.setProperties(key, value); return "配置成功"; } }
|
4、启动类
1 2 3 4 5 6 7 8 9 10
| import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ConfigCenterApplication { public static void main(String[] args) { SpringApplication.run(ConfigCenterApplication.class, args); } }
|
5、配置application.properties
增加如下内容:
1 2
| server.port=8080 zookeeper.url=127.0.0.1:2181
|
6、首先启动本地的zookeeper,再启动ConfigCenterApplication
启动成功后,测试:
浏览器访问:http://127.0.0.1:8080/set/book/java, 设置book的值为java,
再访问 http://127.0.0.1:8080/get/book,获取book的属性值。