一、前言
什么是配置中心?
微服务意味着要将单体应用中的业务拆分成一个个子服务,这些服务都需要必要配置信息才能运行,每个微服务都包含一个类似application.yml的配置文件,单个管理显得极其麻烦,于是集中式的管理思想诞生了,该思想旨在微服务模块之外提供一个集中化的外部配置支持平台,为每个微服务提供配置支持,这个平台称为配置中心。
Spring Cloud Config配置中心?
Spring Cloud Config 就是最早期cloud当中的配置中心,但是需要配合git,svn 或外部存储(例如各种数据库),且需要配合Spring Cloud Bus 实现配置刷新。
Consul注册中心
在https://blog.csdn.net/weixin_43888891/article/details/125511531这一篇文章我们学习了Spring Cloud Consul 作为注册中心的使用方案,且作为Spring Cloud官方推荐替换Eureka 注册中心的方案。
Consul配置中心
Spring Cloud 官方还声明 Consul 可以作为 Spring Cloud Config 配置中心的替代方案。并且不需要额外的git、svn、数据库等配合,且无需配合Bus即可实现配置刷新 。
Consul 使用Go 语言编写,因此具有天然可移植性(支持Linux,Windows和Mac OS);安装包仅包含一个可执行文件,方便部署,与Docker 等轻量级容器可无缝配合。
什么是配置刷新?
所谓配置刷新就是consul配置文件一旦修改,我们应用能立马拿到最新的配置!就比如我们程序有时候经常遇到调用第三方程序接口,我们可以将接口地址配置到注册中心,假如哪天第三方域名修改了,我们不需要重启服务,只需要修改配置中心的配置即可,然后程序能立马拿到最新的访问地址。
Consul 官网:https://www.consul.io/ Consul 官网下载地址:https://www.consul.io/downloads
二、初始化配置
使用Consul作为配置中心,第一步我们先创建目录,把配置信息存储至Consul,点击菜单Key/Value 再点击Create 按钮。 1.创建 config/ 基本目录,可以理解为配置文件所在的最外层文件夹。
这个是官网提出的:
cloud官网:https://docs.spring.io/spring-cloud-consul/docs/current/reference/html/#spring-cloud-consul-config
为什么要用config作为根目录?
consul给我们提供的是key/value存储,也就意味着不仅仅可以存储配置文件,还可以进行存储别的东西,所以这里官网也是提出使用config作为根目录。
2.接下来在config下创建以下文件夹,这些文件夹代表的是应用文件夹,而并不是真正的配置文件!
orderService-dev就代表的是orderService服务的dev环境的应用文件夹。官网 提出的config/testApp, dev/ ,服务与环境区分使用逗号分割 ,读consul的配置的时候默认也是逗号,但是逗号比较丑,我们这里用的-分割,然后我们在读取consul的服务配置文件声明使用-分割即可。
3.创建配置文件,创建文件的时候不带/就是创建文件
在每个应用文件夹下创建配置文件,这里可以选择格式,我使用的YAML格式,注意这里是有语法校验的,假如有空格什么的都会报错的,建议在ider的yml文件写好配置后再进行复制到里面。
配置文件当中的name没有实质意义,就是为了测试 获取不同环境的配置。所以我们每个配置文件当中的name设置成不一样的。
假设以上内容为订单微服务的配置信息,下面我们通过案例来加载Consul配置中心中的配置信息。
三、代码练习
本篇文章采用了maven聚合工程,搭建父工程这些我就不记录了,完全是基于https://blog.csdn.net/weixin_43888891/article/details/125267683文章的项目进行开发的,具体参考这一篇文章!
git源码:https://gitee.com/gzl_com/spring-cloud.git
1. 创建cloud-consul-configdemo8007项目
2. 修改配置
修改pom:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
添加 bootstrap.yml
server:
port: 8007
spring:
application:
name: config-demo
profiles:
active: dev
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
prefix: config
default-context: orderService
profile-separator: '-'
format: yaml
data-key: orderServiceConfig
watch:
enabled: true
delay: 1000
discovery:
register: true
instance-id: ${spring.application.name}-01
service-name: ${spring.application.name}
port: ${server.port}
prefer-ip-address: true
ip-address: ${spring.cloud.client.ip-address}
3. 添加主启动类
@EnableDiscoveryClient 这个注解是服务发现使用的,但是经过试验,当不使用这个注解注册中心照样能注册进去,并且使用RestTemplate 通过服务名称调用服务的时候也没有发现什么问题。所以我怀疑只要是加入了consul服务发现的依赖和配置了consul,就自动开启了,有没有这个注解都可以,针对于这个问题,我专门看了一下我们实际开发当中的项目,他启动类也带了这个注解,所以建议还是加上。
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConfigDemoMain8007 {
public static void main(String[] args) {
SpringApplication.run(ConfigDemoMain8007.class, args);
}
}
4. 读取配置文件
一般读取yml当中的配置文件的方式有两种,一种是使用@ConfigurationProperties 注解以前缀的形式注入到bean当中,一种是以@Value("${name}") 注解的形式注入到属性当中。本篇案例这两种都会练习。
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "mysql")
@Data
public class MysqlProperties {
private String host;
private Integer port;
private String username;
private String password;
}
5. 添加controller
import com.gzl.cn.config.MysqlProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RefreshScope
@RestController
public class ConfigController {
@Autowired
private MysqlProperties mysqlProperties;
@Value("${name}")
private String name;
@GetMapping("/name")
public String getName() {
return name;
}
@GetMapping("/mysql")
public MysqlProperties getMysqlProperties() {
return mysqlProperties;
}
}
最终结构:
6. 启动测试
观察注册中心的服务,已经成功注册上了!
访问:http://localhost:8007/mysql
在项目的配置文件当中我们并没有配置mysql相关属性,访问接口的时候读出来的配置就是从consul上读取的配置。
访问:http://localhost:8007/name
访问出来的name是:order-service-dev,原因就是我们bootstrap的profiles是设置的dev环境。假如设置test就是读取的test的配置
假如我们不设置profiles,读取的就是不带环境的应用名称配置:
7. 动态刷新配置
现在配置文件读取的是dev的,假如修改dev配置环境的配置,过个几秒就会动态刷新配置。所谓动态刷新就是consul配置文件一旦修改,我们应用能立马拿到最新的配置!
动态刷新的时候控制台会有打印日志的,当日志出来之后我们再去访问获取配置的接口,会发现配置已经是最新的了。
Consul 使用 Spring 定时任务 Spring TaskScheduler 来监听配置文件的更新。
默认情况下,它是一个定时任务线程池ThreadPoolTaskScheduler ,其poolSize值为1,要更改TaskScheduler ,请创建-TaskScheduler 用 ConsulConfigAutoConfiguration. CONFIG_WATCH_TASK_SCHEDULER_NAME 常量命名的bean类型,下图是官网说明:
如果 consul 不可用于配置,在某些情况下(如本地开发或某些测试场景)可能会很方便。设置spring.cloud.consul.config.fail-fast=false 将导致配置模块记录警告而不是抛出异常。这将允许应用程序继续正常启动。
四、application.yml与bootstrap.yml的区别
Spring Boot 默认支持 properties(.properties) 和 YAML(.yml .yaml) 两种格式的配置文件,yml和 properties文件都属于配置文件,功能一样。
Spring Cloud 构建于 Spring Boot 之上, 在 Spring Boot 中有两种上下文,一种是bootstrap ,另外一种是 application 。
1. 不使用bootstrap的后果
在springcloud官网,使用consul的案例当中,反复在提示这一句话,那么这到底是为什么呢?
首先在上面示例当中我使用的是bootstrap.yml,并没有使用application.yml,那么使用application.yml到底会有什么后果?
通过将bootstrap改为application后,项目直接启动报错。
在上一篇我写的Consul作为注册中心文章当中,并没有用bootstrap,而是用的application,项目照样运行正常,他和本篇项目最大的区别就是使用了consul的key/value配置,那也就意味着,consul配置中心相关的配置,必须要放到bootstrap.yml当中,下面我们会进行证实这个问题。
2. 两个的区别
区别:
bootstrap.yml 和 application.yml 都可以用来配置参数。- bootstrap.yml 用来程序引导时执行,
应用于更加早期配置信息读取 。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。 - application.yml
可以用来定义应用级别的 , 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。如果搭配 config 使用, application.yml里面定义的文件可以实现动态替换 。
加载顺序:
- 若application.yml 和bootstrap.yml 在同-目录下:
bootstrap.yml 先加载,application.yml后加载 - bootstrap.yml 用于应用程序上下文的引导阶段。bootstrap.yml 由父Spring ApplicationContext加载。
属性覆盖问题:
- application.yml 与 bootstrap 存在相同的配置项,还是
会覆盖 bootstrap ,而 application.yml 里面的内容可以动态替换。
3. 测试application和bootstrap
针对于application和bootstrap两个配置文件的几个场景进行测试:
(1) 测试application和bootstrap属性覆盖的问题
关于覆盖的问题,可以拿上面的案例直接测试,创建application.yml,然后修改端口号为8008,直接启动项目,项目可以启动成功,并且端口是8008,而并没有取bootstrap.yml当中的端口,证明application会覆盖了bootstrap配置的属性 。
(2) 测试在consul的配置文件当中配置了端口,bootstrap也配置了端口,application并没有配置端口
首先运行过程中修改consul当中的端口是不会影响程序的端口的 启动的时候,consul配置的端口会覆盖bootstrap配置的端口,最终会取consul的端口
(3) 测试在consul的配置文件当中配置了端口,bootstrap也配置了端口,application也配置端口
经过测试,发现也是取的consul的配置的端口
通过以上三次测试可以得出结论:consul配置 > application.yml > bootstrap.yml
4. 使用注意
假如我们用到了consul作为配置中心,最重要的一点就是,需要将consul配置中心的相关配置需要放到bootstrap.yml当中,为什么非得放到bootstrap当中?
以上面案例为准,我们的mysql相关配置并没有在项目配置文件配置,完全是基于consul的配置,那也就意味着必须要让consul优先加载,如果consul配置中心相关配置是在application当中,而不在bootstrap,就会导致在程序当中注入mysql相关配置的时候找不到,因为consul还没加载,所以我们必须要让consul的配置中心相关配置放到bootstrap当中。bootstrap会优先与application加载。
bootstrap.yml:
spring:
cloud:
consul:
host: localhost
port: 8500
config:
enabled: true
prefix: config
default-context: orderService
profile-separator: '-'
format: yaml
data-key: orderServiceConfig
watch:
enabled: true
delay: 1000
application.yml:
正常来说除去consul配置中心的相关配置,其余配置是都可以放在consul当中的,就算完全不要application也是可以的。当然profiles.active还是有必要要的,他决定了取consul当中哪个配置文件。
server:
port: 8009
spring:
application:
name: config-demo
profiles:
active: dev
cloud:
consul:
discovery:
register: true
instance-id: ${spring.application.name}-01
service-name: ${spring.application.name}
port: ${server.port}
prefer-ip-address: true
ip-address: ${spring.cloud.client.ip-address}
5. 区分环境
在实际开发当中我们一般都会分为好几个环境,dev、prod、test,不要配置中心的时候还好区分,但是一旦有了配置中心,就意味着又多了个bootstrap.yml配置文件,那我们应该怎么应对多个环境的配置呢?
这是我们项目的方式:
bootstrap-test.properties :就是单纯的放了consul的配置中心相关配置。application-dev.properties :这个就是我们开发时候使用的配置文件,profiles设置为dev,开发的时候根本不使用consul配置中心,consul上的所有配置,在application-dev 上都有,这样就是为了避免共用consul配置,老是有人改consul上的配置。application.properties :就是放了一些基本上不会改变的属性。- 我们用的是docker和jekins,然后发版的时候直接使用profiles设置为test,然后通过
docker run 命令,修改consul的地址。也就是bootstrap-test.properties 存的地址,实际上就是个测试环境的consul地址。
五、总结
HashiCorp 公司的Consul可谓是一款全能组件。可用于提供服务发现和服务配置的工具。用go语言开发,具有很好的可移植性,被Spring Cloud纳入其中。
在注册中心方面, Netflix Eureka停止新版本开发, Consul成为了优秀的可替代方案。
在配置中心方面, Consul 亦可替代 Spring Cloud Config作为配置中心使用,且无需配合Git, SVN等工具,无需配合Bus消息总线即可实现集群配置更新。
一旦使用consul的配置中心,那么配置中心相关配置一定要放到bootstrap.yml当中!
|