# bridge
**Repository Path**: zhangming1/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-08-17
- **Last Updated**: 2024-11-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
Bridge
配置中心 · 管理系统
全量/灰度下发、实例配置项订阅的实时监控、发布回滚、操作日志、配置项监听、权限控制、多环境切换
演示地址( 账号:test 密码:test )
### 目录
- [开发背景](#开发背景)
- [主要功能](#主要功能)
- [使用到的一些技术](#使用到的一些技术)
- [操作界面展示](#操作界面展示)
- [工作台](#工作台)
- [账号管理](#账号管理)
- [团队管理](#团队管理)
- [系统管理](#系统管理)
- [配置项管理](#配置项管理)
- [操作日志](#操作日志)
- [Zookeeper](#Zookeeper)
- [框架原理](#框架原理)
- [控制台搭建](#控制台搭建)
- [客户端接入](#客户端接入)
- [Springboot项目的接入](#Springboot项目的接入)
- [普通Spring项目的接入](#普通Spring项目的接入)
- [如何使用](#如何使用)
- [通过注解的方式使用 (推荐的使用方式)](#通过注解的方式使用 (推荐的使用方式))
- [两点需要注意的地方](#两点需要注意的地方)
- [通过XML的方式使用](#通过XML的方式使用)
- [如何使用监听](#如何使用监听)
- [项目更新日志](#项目更新日志)
### 开发背景
> 本项目主要是为了解决分布式系统中配置杂乱,无法集中管理,和频繁修改配置项后需要重新发布服务的问题。目前提供了“全量/灰度发布、客户端实例配置项订阅情况实时监控、发布回滚、操作历史日志、配置项监听、权限控制、多环境切换(开发、测试、预发、生产)"等功能。
### 主要功能
* 秒级下发配置项,客户端系统动态更新配置项无需重新发布
* 完整的权限体系
* 账号分为三种角色,权限依次递减:**系统管理员**、**团队管理员**、**普通用户**
* **系统管理员**可以操作所有团队下的系统和账号
* **团队管理员**只可以操作自己团队下的系统和团队成员的账号
* **普通用户**只可以操作自己负责的系统
* 记录配置文件操作历史,提供版本回退,减少误操作带来的影响
* 实时监控客户端实例对配置项订阅的情况
* 只需部署一台服务即可,支持多环境切换,不需要dev、test、stable、online各部署一台
* 解决在下发配置项,用户正在读取配置项时发生的“不一致性读”的问题
* 兼容原生的Spring的@Value注解,同时支持 **注解** 和 **XML占位符** 获取配置项
* 对指定的配置项或全部的配置提供监听,方便业务扩展
* 代码侵入性低,集成、部署简单
* 友好的控制台操作页面
### 使用到的一些技术
* Springboot、Mybatis、Maven
* Zookeeper
* Mysql
* Vue.js + Element + iView + Ant Design of Vue
### 操作界面展示
* #### 工作台

* #### 账号管理

* #### 团队管理

* #### 系统管理

* #### 配置项管理

* #### 操作日志

* #### Zookeeper

### 框架原理
* 原理图

### 控制台搭建
* 首先需要准备node.js环境,具体可以参考链接
http://www.runoob.com/nodejs/nodejs-install-setup.html
* 准备zookeeper环境,关于如何安装zookeeper,可以参考下面的链接
https://www.cnblogs.com/Lzf127/p/7155316.html
* 导入Mysql脚本,修改 application.properties 相关配置参数
* 然后进入到模块bridge-console下的doc文件夹下运行脚本进行打包,注意这里不要挪动该脚本的位置
```Shell
sh bridge-package.sh
```
* 然后将打包好的Jar包运行即可,默认的系统管理员账号为admin,密码为admin
* 至此,配置中心后台管理系统搭建完成
### 客户端接入
* #### Springboot项目的接入
> 本项目中提供了配置中心的springboot版本的starter包,对于springboot项目接入非常简单,只需要引入starter包,并在application.properties文件中做简单配置即可。
在 `pom` 中引入以下依赖包
```XML
com.bridge
bridge-spring-boot-starter
${最新的版本号}
```
在 `application.properties` 文件中添加配置项
```Shell
# 系统编码,在控制台新建项目后将该参数配置在此处
spring.bridge.app-code = 294a-56c4-4f18-80df
# 控制台的服务地址
spring.bridge.server-url = http://localhost:8080/bridge
# 环境配置,支持开发、测试、预发、生产 四种环境切换
spring.bridge.env-enum = dev
```
* #### 普通Spring项目的接入
在 `pom` 中引入jar包
```XML
com.bridge.core
bridge-core
${最新的版本号}
```
新建一个 xml 配置文件 `bridge-config.xml` ,写入以下配置后加入Spring中
```XML
```
* 至此接入工作已经全部完成,下面继续看如何使用它
### 如何使用
> 首先我们登录控制台,在指定的团队下新建一个系统A,并指定一个账号作为系统负责人,接着我们将系统A的 `系统编码` 配置在对应的客户端系统中,然后开始添加客户端系统需要的配置项。这里需要注意的是该配置项**第一次新增完成**后,点击 `下发` 时为 **全量下发**,如果不点击 `下发` ,则客户端无法感知到该配置项。如果配置项是已经存在的,做变更操作,这时候是支持**灰度下发**的,因为此时已经有客户端系统的实例订阅了该配置。
经过上面的操作后,我们已经成功在控制台新建好了配置项,接下来我们一起看下如何在客户端系统中使用这个配置项
* #### 通过注解的方式使用 (推荐的使用方式)
```java
package com.sample.springboot;
import com.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);
}
```
* #### 两点需要注意的地方
> 1.其中注解 `@BridgeValue(key = "boolean", propertyName = "abBoolean")` 中的 `key` 为配置项名称,`propertyName` 为成员变量名称。
2.特别需要注意的是**不要将配置项直接在使用的地方直接配置**,具体看下面的例子。
```java
package com.sample.springboot;
import com.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.sample.springboot;
import com.bridge.annotation.BridgeValueChangedListener;
import com.bridge.listener.PropertiesChangeListener;
import com.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` 可以传入一个数组,当有值传入的时候则会监听传入的配置项,如果不传任何参数则监听所有的配置项。
### 项目更新日志
##### 2019-03-19 v1.0.0 项目初步开发完成
* 项目开发、测试完成