01 Spring Cloud Config

Wu Jun 2020-03-17 13:50:43
10 微服务 > 2 配置中心

Spring Cloud Config 老版采用 git 或 svn 存储配置文件,默认情况下使用 git。从 Edgware 版本开始新增的一种配置方式:采用数据库存储配置信息。

1 结构与原理

Spring Cloud Config 分服务端和客户端,服务端负责将 git(svn)中存储的配置文件发布成 REST 接口,客户端可以从服务端 REST 接口获取配置。

原理

2 Git 示例

2.1 准备 git

准备 git 仓库,放置配置文件

test-config-dev.properties:test=dev
test-config-pro.properties:test=pro

2.2 构建配置中心

配置中心负责从配置仓库读取配置,并提供接口访问

1)pom 依赖
<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-config-server</artifactId>
	</dependency>
</dependencies>
2)配置文件

如果 Git 仓库需要权限,配置 username、password,否则不用

spring.application.name=config-server
server.port=8001

spring.cloud.config.server.git.uri=https://github.com/……    # 配置git仓库的地址
spring.cloud.config.server.git.searchPaths=respo  # 仓库下相对地址,可配多个,逗号分割。
spring.cloud.config.label=master # 配置仓库的分支
spring.cloud.config.server.git.username=# git仓库的账号
spring.cloud.config.server.git.password=# git仓库的密码
3)启动类

添加 @EnableConfigServer 注解,开启 Spring Cloud Config 的服务端功能。

@EnableConfigServer
@SpringBootApplication
public class Application {

访问配置信息的 URL 与配置文件的映射关系如下:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

上面的 url 会映射 {application}-{profile}.properties 对应的配置文件,其中 {label} 对应 Git 上不同的分支,默认为 master。

2.3 构建客户端

1)pom 依赖
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-config</artifactId>
	</dependency>
2)配置文件

application.properties:

//对应{application}部分
spring.application.name=config-client
server.port=8002

bootstrap.properties:

config 相关属性必须配置在 bootstrap.properties 中,先于 application.properties,才能被正确加载。

spring.cloud.config.name=neo-config
spring.cloud.config.profile=dev
spring.cloud.config.uri=http://localhost:8001/
spring.cloud.config.label=master
3)启动类

添加 @EnableConfigServer,激活对配置中心的支持

@SpringBootApplication
public class ConfigClientApplication {
4)取值

像使用本地配置文件一样,使用 @Value 注解来获取 server 端参数的值

2.4 高可用

spring.cloud.config.uri
改为
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=config-server

2.5 配置刷新

1)基础方法

同 Git 仓库的 Web Hook 功能进行关联,当有 Git 提交变化时,就给对应的配置主机发送 /refresh 请求来实现配置信息的实时更新。

  1. 添加依赖
    pom 添加spring-boot-starter-actuator模块,监控状态,包括 /refresh 功能

  2. 开启更新机制
    给加载变量的类上面加载 @RefreshScope ,在客户端执行 /refresh 的时候就会更新此类下面的变量值。

2)消息总线
  1. 原理
    服务端和客户端都配置消息,配置后 WebHook 触发服务端,服务端通过 Spring Cloud Bus 广播 /refresh,客户端收到消息都去更新配置。

  2. 配置
    以 RabbitMq 为例,服务端和客户端都添加spring-cloud-starter-bus-amqp依赖,配置文件增加 RabbitMq 相关配置,订阅同一频道,关闭安全验证。management.security.enabled=false

  3. 步骤
    3.1 提交代码 WebHook 触发 post 请求给 bus/refresh
    3.2 server 端接收到请求并发送给 Spring Cloud Bus
    3.3 Spring Cloud bus 接到消息并通知给其它客户端
    3.4 其它客户端接收到通知,请求 Server 端获取最新配置
    3.5 全部客户端均获取到最新的配置

2.6 安全控制

1)url 连接加密

如果觉得直接访问 config-server 的 url 不安全,可以使用 Spring Security 进行安全控制 。

(1) config-server端配置

pom 依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

配置文件

security:
  user:
    password: 123456
    name: user
(2)config-client 端配置

配置文件中添加验证信息

spring.cloud.config.username=user
spring.cloud.config.password=123456
2)数据传输加密

Spring Cloud Config 提供了对敏感信息进行加密解密的功能。
在属性值前使用{cipher}前缀来标注该内容是一个加密值,当微服务客户端来加载配置时,配置中心会自动的为带有{cipher}前缀的值进行解密。

3 数据库示例

3.1 pom 依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.11.RELEASE</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.flywaydb</groupId>
        <artifactId>flyway-core</artifactId>
        <version>5.0.3</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.21</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

3.2 准备 schema 创建文件。

在 resources 下创建 schema 目录,并加入 V1_Base_version.sql 文件,该脚本会在程序运行时由 flyway自动执行

CREATE TABLE `properties` (
  `id` int(11) NOT NULL,
  `key` varchar(50) NOT NULL,
  `value` varchar(500) NOT NULL,
  `application` varchar(50) NOT NULL,
  `profile` varchar(50) NOT NULL,
  `label` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.3 创建应用主类

@EnableConfigServer
@SpringBootApplication
public class ConfigServerBootstrap {
    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ConfigServerBootstrap.class);
        // 测试用数据,仅用于本文测试使用
        JdbcTemplate jdbcTemplate = context.getBean(JdbcTemplate.class);
        jdbcTemplate.execute("delete from properties");
        jdbcTemplate.execute("INSERT INTO properties VALUES(1, 'com.message', 'test-stage-master', 'config-client', 'stage', 'master')");
        jdbcTemplate.execute("INSERT INTO properties VALUES(2, 'com.message', 'test-online-master', 'config-client', 'online', 'master')");
        jdbcTemplate.execute("INSERT INTO properties VALUES(3, 'com.message', 'test-online-develop', 'config-client', 'online', 'develop')");
        jdbcTemplate.execute("INSERT INTO properties VALUES(4, 'com.message', 'hello-online-master', 'hello-service', 'online', 'master')");
        jdbcTemplate.execute("INSERT INTO properties VALUES(5, 'com.message', 'hello-online-develop', 'hello-service', 'online', 'develop')");
    }
}

3.4 配置 application.properties

spring.application.name=config-server-db
server.port=10020
//将配置中心的存储实现切换到jdbc的方式
spring.profiles.active=jdbc
//由于采用mysql数据源,key、value是保留关键词,原生的实现语句会报错,所以重写一下查询语句
spring.cloud.config.server.jdbc.sql=SELECT `KEY`, `VALUE` from PROPERTIES where APPLICATION=? and PROFILE=? and LABEL=?

spring.datasource.url=jdbc:mysql://localhost:3306/config-server-db
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

//flyway加载schema创建sql的位置
flyway.locations=/schema