目录
分布式配置(Spring Cloud Config)
分布式配置(Spring Cloud Config)
随着项目越来越大,模块越来越多,配置文件少则四五个多则二三十个,配置放代码和配置文件里不够安全,放Maven里不够优雅,放环境变量里是够安全,随着docker的流行也还算方便,可不能统一管理,况且还要写个脚本往环境变量里写,这都太麻烦了,能不能用一个优雅,安全又方便统一管理的方法来解决这些问题呢,Spring Cloud Config就是一个比较好的解决方案;也就是:存放配置文件
Spring Cloud Config为分布式系统中的外部化配置提供服务器端和客户端支持。使用Config Server,可以在中心位置管理所有环境中应用程序的外部属性;方便部署与运维。分客户端、服务端。
Spring Cloud Config是一种用来动态获取Git、SVN、数据库、本地的配置文件等的一种工具;即把应用原本放在本地文件的配置抽取出来放在中心服务器,本质是配置信息从本地迁移到云端。从而能够提供更好的管理、发布能力
Spring Cloud Config分服务端和客户端,服务端负责将git(svn)中存储的配置文件发布成REST接口,客户端可以从服务端REST接口获取配置。但客户端并不能主动感知到配置的变化,从而主动去获取新的配置,这需要每个客户端通过POST方法触发各自的/refresh
主要从以下三块来说一下Config的使用
1.基础版的配置中心(不集成Eureka)
2.结合Eureka版的配置中心
3.实现配置的自动刷新
(1)服务端:提供配置信息
服务端也称分布式配置中心,是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密/解密信息等访问接口
(2)客户端:从配置中心拉取配置信息
客户端则是通过指定配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。默认采用git,并且可以通过git客户端工具来方便管理和访问配置内容
客户端和服务器上的概念与Spring Environment和PropertySource抽象,因此它们非常适合Spring应用程序,但可以与以任何语言运行的任何应用程序一起使用。在应用程序从开发人员到测试人员再到生产人员的整个部署管道中进行移动时,可以管理这些环境之间的配置,并确保应用程序具有它们迁移时所需的一切。服务器存储后端的默认实现使用Git,因此它可以轻松支持配置环境的标记版本,并且可以通过各种工具来访问这些内容来管理内容。添加替代实现并将其插入Spring配置很容易
分布式配置优点
(1)集中管理配置文件
(2)不同环境不同配置,动态化的配置更新
(3)运行期间,不需要去服务器修改配置文件,服务会想配置中心拉取自己的信息
(4)配置信息改变时,不需要重启即可更新配置信息到服务
(5)配置信息以rest接口暴露
注意:之前一般用各种starter,而这个config server不是spring-cloud-starter-config-server(无)而是spring-cloud-config-server
实现最简单的配置中心
启动一个服务作为服务方,之后各个需要获取配置的服务作为客户端来这个服务方获取配置。
(1)Git仓库
在github创建仓库,然后创建配置文件;如下图
注意:配置文件名称不是乱起的
例如:上面的config-single-client-dev.yml和config-single-client-prod.yml这两个是同一个项目的不同版本,项目名称为config-single-client,一个对应开发版,一个对应正式版。
config-eureka-client-dev.yml和config-eureka-client-prod.yml则是另外一个项目的,项目的名称就是config-eureka-client
(2)服务端
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Config服务端包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2.application配置
Spring Cloud Config Server从各种来源提取远程客户端的配置
application中从Git存储库(必须提供)中获取配置
①:application.yml
server:
port: 3301
spring:
application:
name: config-server # 应用名称
cloud:
config:
server:
git:
uri: https://github.com/demo/config-demo.git # 配置文件所在仓库
username: github # 登录账号
password: github # 登录密码
default-label: master # 配置文件分支
search-paths: config # 配置文件所在根目录
②:application.properties
server.port=3301
spring.cloud.config.server.default-application-name=config-server
#配置Git仓库地址
spring.cloud.config.server.git.uri=https://github.com/demo/config-demo.git
#如果Git仓库为公开仓库,可以不填写用户名和密码,如果是私有仓库需要填写
#访问Git仓库的用户名
spring.cloud.config.server.git.username=xxxxoooo
#访问Git仓库的用户密码
spring.cloud.config.server.git.password=xxxxoooo
#配置仓库的分支
spring.cloud.config.label=master
#配置仓库路径
spring.cloud.config.server.git.search-paths=config-path
3.启动类添加@EnableConfigServer
@SpringBootApplication
@EnableConfigServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动服务测试
4.访问规则
Config支持使用的请求的参数规则:
/ {application} / {profile} [/ {label}] ==> / { 应用名 } / { 环境名 } [ / { 分支名 } ]
规则:
规则 | 描述 |
---|---|
/{application}-{profile}.yml | / { 应用名 } - { 环境名 }.yml |
/{label}/{application}-{profile}.yml | / { 分支名 } / { 应用名 } - { 环境名 }.yml |
/{application}-{profile}.properties | / { 应用名 } - { 环境名 }.properties |
/{label}/{application}-{profile}.properties | / { 分支名 } / { 应用名 } - { 环境名 }.properties |
注意:第一个规则的分支名(label)是可以省略的,默认是master分支
无论配置文件是properties,还是yml,只要是“[应用名]+[环境名]”能匹配到这个配置文件,那么就能取到
①:如果是想直接定位到没有写环境名的默认配置,那么就可以使用default去匹配没有环境名的配置文件
②:如果直接使用应用名来匹配,会出现404错误,此时可以加上分支名匹配到默认配置文件
③:如果配置文件的命名很由多个“-”分隔,此时直接使用这个文件名去匹配的话,会出现直接将内容以源配置文件内容直接返回,内容前可能会有默认配置文件的内容(已测试)
参数 | 描述 |
---|---|
{application} | 应用名称。对应到配置文件上来,就是配置文件的名称部分,例如我上面创建的配置文件 |
{profile} | 配置文件的版本。项目有开发版本、测试环境版本、生产环境版本,对应到配置文件上来就是以application-{profile}.yml加以区分。例如:application-dev.yml、application-sit.yml、application-prod.yml |
{label} | 表示GIT分支,默认是master分支。如果项目是以分支做区分也是可以的,那就可以通过不同的label来控制访问不同的配置文件了 |
application可以自定义为其它的名称,这里可以用应用的名称,即应用名,后边的dev、stable、prod这些都可以视为一个应用下多个不同的配置文件,可以当做环境名
下面的5条规则中,只看前三条,因为这里的配置文件都是yml格式的。根据这三条规则,可以通过以下地址查看配置文件内容:
http://localhost:3301/config-client/dev/master
http://localhost:3301/config-client/prod
http://localhost:3301/config-client-dev.yml
http://localhost:3301/config-client-prod.yml
http://localhost:3301/master/config-client-prod.yml
通过访问以上地址,如果可以正常返回数据,则说明配置中心服务端一切正常
(3)客户端
1.导入Spring Cloud Config依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Cloud Config客户端包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2.application配置
spring:
profiles:
active: dev
---
spring:
profiles: prod
application:
name: config-client
cloud:
config:
uri: http://localhost:3301
label: master
profile: prod
---
spring:
profiles: dev
application:
name: config-client
cloud:
config:
uri: http://localhost:3301
label: master
profile: dev
配置了两个版本的配置,并通过spring.profiles.active设置当前使用的版本。例如:本例中使用的dev版本
3.启动类
@SpringBootApplication
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
4.读取配置信息
要读取配置中心的内容,需要增加相关的配置类,Spring Cloud Config读取配置中心内容的方式和读取本地配置文件中的配置是一模一样的。可以通过@Value或@ConfigurationProperties来获取配置
Git配置文件(application.yml)
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
data:
env: NaN
username: NaN
password: NaN
其中management是关于actuator相关的,接下来自动刷新配置的时候需要使用。
data部分是当无法读取配置中心的配置时,使用此配置,以免项目无法启动
①:使用@Value获取配置
@Data
@Component
public class GitConfig {
@Value("${data.env}")
private String env;
@Value("${data.username}")
private String username;
@Value("${data.password}")
private String password;
}
②:使用@ConfigurationProperties获取配置
@Component
@Data
@ConfigurationProperties(prefix = "data")
public class GitConfig {
private String env;
private String username;
private String password;
}
实现自动刷新
Spring Cloud Config在项目启动时加载配置内容这一机制,导致了它存在一个缺陷,修改配置文件内容后,不会自动刷新。
当服务已经启动的时候,去修改github上的配置文件内容,这时候,再次刷新页面,还是旧的配置内容,新内容不会主动刷新过来。但是,总不能每次修改了配置后重启服务吧。如果是那样的话,还是不要用它了为好,直接用本地配置文件岂不是更快。
提供了一个刷新机制,但是需要主动触发。那就是@RefreshScope注解并结合actuator,注意:要引入spring-boot-starter-actuator包
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
在config-client客户端配置中增加actuator配置
management:
endpoint:
shutdown:
enabled: false
endpoints:
web:
exposure:
include: "*"
主要用到的是 refresh 这个接口
在需要读取配置的类上增加@RefreshScope注解,在Controller中使用配置
@RestController
@RefreshScope
public class GitController {
@Autowired
private GitConfig gitConfig;
@Autowired
private GitAutoRefreshConfig gitAutoRefreshConfig;
@GetMapping(value = "show")
public Object show(){
return gitConfig;
}
@GetMapping(value = "autoShow")
public Object autoShow(){
return gitAutoRefreshConfig;
}
}
注意:以上都是在client客户端做的修改
①:之后,重启client端,重启后,修改github上的配置文件内容,并提交更改,再次刷新页面,没有反应。没有问题。
②:接下来,发送POST请求到http://localhost:3302/actuator/refresh这个接口,用postman之类的工具即可,此接口就是用来触发加载新配置的,返回内容如下:
[
"config.client.version",
"data.env"
]
之后,再次访问RESTful接口,http://localhost:3302/autoShow 这个接口获取的数据已经是最新的了,说明refresh机制起作用了。而http://localhost:3302/show获取的还是旧数据,这与@Value注解的实现有关,所以,在项目中就不要使用这种方式加载配置了