# bridge **Repository Path**: sunyinhui/bridge ## Basic Information - **Project Name**: bridge - **Description**: 基于zookeeper实现的一个配置中心系统,可以动态发布配置项,客户端系统订阅后可以即时感知,无需重启服务 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 162 - **Created**: 2019-03-21 - **Last Updated**: 2024-12-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [![输开源协议](https://img.shields.io/badge/License-Apache--2.0-brightgreen.svg "Apache")](https://www.apache.org/licenses/LICENSE-2.0) # 配置中心系统 ### 项目更新日志 ##### 2019-03-19 v1.0.0 项目初步开发完成 * 项目开发、测试完成 ### 开发背景 > 本项目主要是为了解决分布式系统中配置杂乱,无法集中管理,和频繁修改配置项后需要重新发布服务的问题。同时提供了客户端订阅情况的监控和回滚配置项等功能。 ### 主要功能 * 秒级下发配置项,客户端系统动态更新配置项无需重新发布 * 完整的权限体系 * 账号分为三种角色,权限依次递减:**系统管理员**、**团队管理员**、**普通用户** * **系统管理员**可以操作所有团队下的系统和账号 * **团队管理员**只可以操作自己团队下的系统和团队成员的账号 * **普通用户**只可以操作自己负责的系统 * 记录配置文件操作历史,提供版本回退,减少误操作带来的影响 * 实时监控客户端实例对配置项订阅的情况 * 只需部署一台服务即可,支持多环境切换,不需要dev、test、stable、online各部署一台 * 解决在下发配置项,用户正在读取配置项时发生的“不一致性读”的问题 * 兼容原生的Spring的@Value注解,同时支持 **注解** 和 **XML占位符** 获取配置项 * 对指定的配置项或全部的配置提供监听,方便业务扩展 * 代码侵入性低,集成、部署简单 * 友好的控制台操作页面 ### 使用到的一些技术 * Springboot、Mybatis、Maven * Zookeeper * Mysql * Vue.js + Element + iView + Ant Design of Vue ### 操作界面展示 * `工作台` 页面

![工作台页面](https://images.gitee.com/uploads/images/2019/0321/142127_3e3da83d_718145.png "工作台.png") * `账号管理` 页面

![账号管理](https://images.gitee.com/uploads/images/2019/0321/142216_c56dcc72_718145.png "账号管理.png") * `团队管理` 页面

![团队管理](https://images.gitee.com/uploads/images/2019/0321/142314_ad343299_718145.png "团队管理.png") * `系统管理` 页面

![系统管理](https://images.gitee.com/uploads/images/2019/0321/142348_89093995_718145.png "系统管理.png") * `配置项管理` 页面

![配置项管理](https://images.gitee.com/uploads/images/2019/0321/142431_11267357_718145.png "配置项管理.png") * `操作日志` 页面

![操作日志](https://images.gitee.com/uploads/images/2019/0321/142517_99fbda1b_718145.png "操作日志.png") * `zookeeper` 页面

![zookeeper](https://images.gitee.com/uploads/images/2019/0321/145128_b47ec21d_718145.png "zookeeper数据.png") ### 框架原理 * 原理图 ![原理图](https://images.gitee.com/uploads/images/2019/0320/144259_d375f8c0_718145.png "原理图.png") ### 控制台搭建 * 首先需要准备node.js环境,具体可以参考链接 http://www.runoob.com/nodejs/nodejs-install-setup.html * 准备zookeeper环境,关于如何安装zookeeper,可以参考下面的链接 https://www.cnblogs.com/Lzf127/p/7155316.html * 导入Mysql脚本,修改 application.properties 相关配置参数 * 然后进入到项目根目录下进行打包,运行命令,这里的区分 Linux 和 Windows 环境 ```Shell # linux环境执行 mvn clean package linux # windows环境执行 mvn clean package win ``` * 然后将打包好的Jar包运行即可,默认的系统管理员账号admin,密码为111111 * 至此,配置中心后台管理系统搭建完成 ### 客户端接入 * Springboot项目的接入 > 本项目中提供了配置中心的springboot版本的starter包,对于springboot项目接入非常简单,只需要引入starter包,并在application.properties文件中做简单配置即可。 在 `pom` 中引入以下依赖包 ```XML com.bridge bridge-spring-boot-starter ${最新的版本号} org.springframework.boot spring-boot-starter-aop ``` 在 `application.properties` 文件中添加配置项 ```Shell # 系统编码,在控制台新建项目后将该参数配置在此处 spring.bridge.app-code = 294a-56c4-4f18-80df # 控制台的服务地址 spring.bridge.server-url = http://localhost:8080/bridge # 环境配置,支持开发、测试、预发、生产 四种环境切换 spring.bridge.env-enum = dev ``` 在启动类上加上注解 ```java @ComponentScan({"com.sun.bridge.consistency.aop","你自己项目需要扫描的包路径"}) ``` * 普通Spring项目的接入 在 `pom` 中引入jar包 ```XML com.bridge.core bridge-core ${最新的版本号} ``` 新建一个 xml 配置文件 `bridge-config.xml` ,写入以下配置后加入Spring中 ```XML ``` * 至此接入工作已经全部完成,下面继续看如何使用它 ### 如何使用 * 首先我们登录控制台,在指定的团队下新建一个系统A,并指定一个账号作为系统负责人,接着我们将系统A的 `系统编码` 配置在对应的客户端系统中,然后开始添加客户端系统需要的配置项。这里需要注意的是该配置项**第一次新增完成**后,点击 `下发` 时为 **全量下发**,如果不点击 `下发` ,则客户端无法感知到该配置项。如果配置项是已经存在的,做变更操作,这时候是支持**灰度下发**的,因为此时已经有客户端系统的实例订阅了该配置。 * 经过上面的操作后,我们已经成功在控制台新建好了配置项,接下来我们一起看下如何在客户端系统中使用这个配置项 * 通过 **注解** 的方式使用,请看下面的这个例子 ```java package com.bridge.springboot; import com.sun.bridge.annotation.BridgeValue; import lombok.Data; import org.springframework.stereotype.Component; import java.math.BigDecimal; /** * @author Jay * @version v1.0 * @description 请添加类描述 * @date 2019-01-16 14:33 */ @Data @Component public class TestComponent { public String abString; public Integer abInteger; public BigDecimal abBigDecimal; public Long abLong; public Short abShort; public Double abDouble; public Float abFloat; public Boolean abBoolean; @BridgeValue(key = "string", propertyName = "abString") public String getAbString() { return abString; } @BridgeValue(key = "integer", propertyName = "abInteger") public Integer getAbInteger() { return abInteger; } @BridgeValue(key = "bigDecimal", propertyName = "abBigDecimal") public BigDecimal getAbBigDecimal() { return abBigDecimal; } @BridgeValue(key = "long", propertyName = "abLong") public Long getAbLong() { return abLong; } @BridgeValue(key = "short", propertyName = "abShort") public Short getAbShort() { return abShort; } @BridgeValue(key = "double", propertyName = "abDouble") public Double getAbDouble() { return abDouble; } @BridgeValue(key = "float", propertyName = "abFloat") public Float getAbFloat() { return abFloat; } @BridgeValue(key = "boolean", propertyName = "abBoolean") public Boolean getAbBoolean() { return abBoolean; } } ``` 接下来我们可以使用了 ```java @Autowired private TestComponent testComponent; @RequestMapping("/test") @ResponseBody public Result test() { BigDecimal data = testComponent.getAbBigDecimal(); return RpcResponse.wrapSuccessfulResult(data); } ``` **这里有以下3点需要注意:** > 1.这里对成员变量的get方法一定要是标准的get方法,如成员变量为testOne,则get方法为getTestOne()。
2.其中注解 `@BridgeValue(key = "boolean", propertyName = "abBoolean")` 中的 `key` 为配置项名称,`propertyName` 为成员变量名称。
3.特别需要注意的是**不要将配置项直接在使用的地方直接配置**,具体看下面的例子。 ```java package com.bridge.springboot; import com.sun.bridge.annotation.BridgeValue; import lombok.Data; import org.springframework.stereotype.Service; /** * @author Jay * @version v1.0 * @description 请添加类描述 * @date 2019-01-16 14:33 */ @Data @Service public class TestService { public String abString; @BridgeValue(key = "string", propertyName = "abString") public String getAbString() { return abString; } /** * 不要直接在TestService内引入该配置项后直接在这里使用, * 因为spring的aop无法拦截到上面getAbString()方法, * 这样做虽然可以获取到最新值,但会存在“不一致性读的”隐患 * * @return */ public String say(){ return "say: ".concat(getAbString()).concat(getAbString()); } } ``` * 通过 **XML** 的方式使用,请看下面的这个例子 当上面这个TestBO的所有成员变量为配置项时,我们可以通过在xml中配置bean的方式去实现配置 ```XML ``` 只要使用 `@Bridge{配置项}` 即可。通过 `XML` 的方式使用时,如果没有办法在对应成员变量所在的类中添加对应的get方法并添加 `@BridgeValue(key = "xxx.xx", propertyName = "xxxx")` 注解,还是会存在**不一致性读**的问题,所以此种方式不推荐用户使用。 * 如何使用监听
在介绍完接入的方法后,接下来我们一起来看看如何添加对指定配置项的监听,可以参考下面的例子 ```java package com.bridge.springboot; import com.sun.bridge.annotation.BridgeValueChangedListener; import com.sun.bridge.listener.PropertiesChangeListener; import com.sun.bridge.zookeeper.data.ConfigKeyNodeData; import lombok.extern.slf4j.Slf4j; /** * @author Jay * @version v1.0 * @description 请添加类描述 * @date 2019-02-19 14:49 */ @Slf4j @BridgeValueChangedListener(key = "test.one.two") public class ListenerTest implements PropertiesChangeListener { /** * 当值发生变化前 * * @param configKeyNodeData */ @Override public void onBeforePropertiesChanged(ConfigKeyNodeData configKeyNodeData) { log.info("当值发生变化前,接收到回调------>:{}", configKeyNodeData); } /** * 当值发生变化后 * * @param configKeyNodeData */ @Override public void onPropertiesChanged(ConfigKeyNodeData configKeyNodeData) { log.info("接收到回调------>:{}", configKeyNodeData); } } ``` 这里注解 `@BridgeValueChangedListener(key = "test.one.two")` 中的 `key` 可以传入一个数组,当有值传入的时候则会监听传入的配置项,如果不传任何参数则监听所有的配置项。