Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持。配置服务器为各应用的所有环境提供了一个中心化的外部配置。Spring Cloud Config具有中心化、版本控制、支持动态更新和语言独立等特性。配置服务器默认采用Git来存储配置信息,使用Git作为配置的后端存储,有助于对环境配置进行版本管理,同时也方便相关人员进行管理和访问。同时,配置服务器还支持SVN、本地文件、JDBC、Redis、AWS S3、CredHub等存储配置方式。
在Spring Cloud Config中分为客户端、服务端两类角色。其中服务端主要提供了集中管理配置资源、多种存储配置信息方式等能力,配置服务器可以很容易的集成注册中心,构建高可用的配置服务。客户端主要就是指那些需要使用这些配置文件的应用服务。下面我们先梳理一下其中的工作流程,参考上面的系统架构图:
首先,服务端启动,默认不加载在Git或其他存储方式下的配置信息。
然后,客户端启动时,会根据bootstrap.properties中配置的应用名称(spring. application.name)、环境名(spring.profiles.active)、版本分支(spring.cloud.config.label),向配置服务器请求获取配置数据。
然后,服务端会根据应用名称、环境名称、版本分支进行配置信息加载,并把加载到的信息拉去到本地,建立本地缓存。
然后,根据拉取的信息创建Spring的ApplicationContext实例,并将该配置信息返回给客户端。
最后,客户端获取到这些配置信息后,将这些配置数据加载到自己的上下文中(这些配置信息优先级高于本地的配置信息)。
配置服务可以在一个现有的应用基础上搭建,也可以单独搭建一个配置服务的应用,这里我们选择了后者。这里选择使用默认的Git作为配置信息存储方式。准备了Git仓库:https://gitee.com/hsh2015/qriver-cloud-learning.git,其中的配置文件如下:
其中spring-cloud-config-server是核心的依赖,而spring-cloud-starter-netflix-eureka-client为了实现把配置服务注册到注册中心而引入的。
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-config-server
spring.application.name=config-server
server.port=8090
#设置与Eureka Server交互的地址。
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/
#git地址
spring.cloud.config.server.git.uri=https://gitee.com/hsh2015/qriver-cloud-learning.git
#git用户名
spring.cloud.config.server.git.username=xxx
#git密码
spring.cloud.config.server.git.password=xxx
#指定配置文件的存储目录
spring.cloud.config.server.git.search-paths=config-repo
上述配置信息中:
主要通过@EnableConfigServer注解启用注册服务功能,通过@EnableDiscoveryClient注解进行服务的注册。
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
完成上述配置后,我们可以通过访问http://localhost:8090/config-clientA/dev/master 进行验证,页面上会输出如下内容,说明配置服务器搭建成功了。
{"name":"config-clientA","profiles":["dev"],"label":"master","version":"a6cc89b37c925028c428b4c18ee13f391d1a0004","state":null,"propertySources":[{"name":"https://gitee.com/hsh2015/qriver-cloud-learning.git/config-repo/config-clientA-dev.properties","source":{"logging.level.org.springframework":"debug"}},{"name":"https://gitee.com/hsh2015/qriver-cloud-learning.git/config-repo/config-clientA.properties","source":{"logging.level.org.springframework":"error"}}]}
访问路径格式:/{application}/{profile}[/{label}],其中application、profile、label分别对应应用名称、环境名和分支版本,profile默认值为default,label的默认值为master。
客户端就是使用分布式配置信息的应用服务,一般都是分布式系统中的其他微服务。这里创建一个config-clientA应用,演示客户端使用方式。
在原来的的pom文件的基础上,引入config相关依赖即可,如下所示:
org.springframework.cloud
spring-cloud-starter-config
spring.application.name=config-clientA
server.port=8091
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/
#spring.cloud.config.uri=http://127.0.0.1:8090
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.serviceId=config-server
spring.cloud.config.profile=dev
spring.cloud.config.label=master
其中
这里需要注意的是: Git仓库中配置文件的命名规则约定:{application}-{profile}.properties 或 {application}-{profile}.yml,其中application是客户端的spring.application.name对应的参数值。
这个启动类不需要因为使用分布式配置信息而做特殊处理,就是一个普通的启动类。
因为bootstrap.properties配置文件中使用了profile=dev,所以会使用config-clientA-dev.properties,该配置中启用了spring的Debug模式。启动客户端服务后,会发现控制台会打印Spring的Debug级别的日志,默认是Info级别。
配置服务器的高可用性问题是在生产环境必须考虑和解决的问题,因为配置服务是影响全局的,如果出现不可用,可能会引起生产事故的。
如何实现配置服务的高可用性,其实在前面的实例中,我们已经应用到了相关知识点,即把配置服务实例注册到注册中心,客户端通过注册中心发现并使用对应的服务。如果我们启动了多个配置服务实例,然后注册到注册中心,而客户端只是根据服务名称进行服务调用,这个时候其实就实现了高可用的配置。
在上面客户端应用中,我们添加一个测试类ConfigTestController,用来验证配置文件中的参数,如下所示:
@RestController
//@RefreshScope
public class ConfigTestController {
@Value("${test.config}")
private String testStr;
@RequestMapping("getStr")
public String getTestStr(){
return testStr;
}
}
需要在Git库对应的配置文件中添加对应的test.config属性,如下所示:
#自定义,测试数据
test.config = bbb
重新启动客户端服务,访问http://localhost:8091/getStr ,在页面返回了“bbb”字符串。然后,修改上述test.config属性值为aaa,然后再访问http://localhost:8091/getStr ,发现返回的还是“bbb”,为什么会这样的呢?如果这个时候,我们通过http://localhost:8090/config-clientA/dev/master 查看服务端的配置文件,发现其实已经发现修改了,这说明是客户端服务没有监控到配置信息的变化。我们可以通过引入spring-boot-starter-actuator依赖,提供刷新配置的功能。
首先,在pom文件中引入actuator相关依赖,如下所示:
org.springframework.boot
spring-boot-starter-actuator
如果不增加如下配置,访问http://localhost:8091/actuator/refresh 时,会出现404错误。
#actuator相关配置
management.endpoints.web.exposure.include=*
重启启动后,每次修改Git配置后,访问http://localhost:8091/actuator/refresh 进行配置刷新,然后再访问时就会发现可以看到最新修改后的信息了。这时候说明修改已经被客户端获取到了,不过有心的童鞋会发现,每次都要通过/actuator/refresh刷新很麻烦,还有如果有很多客户端服务难道需要每次把所有的客户端服务全部刷新一遍吗?答案当然是否定,后面我们再继续学习如何结合Spring Cloud Bus来实现以消息总线的方式进行通知配置信息的变化,完成集群上的自动化更新。