在 微服务架构概念索引 一文中介绍了整个云源生应用的搭建体系,后续的内容将会从Spring Cloud从技术架构,到基础设置再到团队协作方式一点一滴的记录搭建整个云服务的过程。现在从最基本的中心化配置开始介绍。
Spring基金会项目繁多、种类各异,但是他们都脱离不了一个基本的要求——基于 Spring Ioc的配置 。Spring的基础在于IoC容器,各种各样的项目都在IoC容器的基础之上扩展而来。在 设计模式与IoC 中已经介绍了IoCs的目的就是解决数据与Bean的关系、以及Bean与Bean之间的关系。
在单Jvm的Spring应用中各种配置文件都是通过 Profile 结合 PropertySource 进行管理,而到了 Spring Boot 则提供了大量的默认配置简化了这个过程。而在Spring Cloud中需要管理大量的节点,中心化配置的需求随之而产生。
Spring Cloud的中心化配置并没有什么特别神奇的地方,实际上就是把本该放到本地的配置文件(例如application.yml)统一放置到一个仓库中。然后用一个Web服务来管理仓库,其他微服务节点从这个Web服务获取配置文件。所以就算没有Spring Cloud Config提供这个功能,我们也可以自己编码在ApplicationContext的启动装载IoC之前先处理好配置。
在假设有别的Spring Cloud知识之前,本文介绍不使用Netflix和Eureka注册服务的来管理中心化配置的方法。
上图是Spring Cloud Config的基本结构。左侧是一系列的微服务节点,右侧是他们对应的配置文件。例如Node-1服务对应的是 node-1-config.yml 文件,在单一的应用中本来 node-1-config.yml 文件应该是放置在Node-1工程的classpath下的,现在的区别是将他们分开,将配置文件统一放置到一个仓库中,然后用Config-Service来管理。
中心化配置就是这么简单,除了把配置文件拆走其他的使用方式完全一样,可以通过 PropertySources或@Value注解 来获取配置的参数。
至于中心化配置有什么好处就不用一一细说了,除了在负载均衡中减少配置之外,也便于环境管理等等。
清楚原理之后做事就简单了,案例代码一共包含三个工程( github源码 ),分别是 configuration-server 、 configuration-node-1 和 configuration-node-2 。configuration-server就是图中的Config-Service,他为所有的微服务节点提供中心化配置服务,所有的配置都在独立的 git仓库中 ,在某个微服务节点请求配置数据的时候, configuration-server 会去仓库中获取对应的配置并传输给微服务节点。
Spring Cloud的中心化配置服务通过Http请求提供配置管理服务,所以他自身也是一个Web。要启用的配置服务就2步:1.写一个配置文件指定服务端口和配置文件仓库,2.启动Spring Web服务。
下面 application.yml
指定了中心化服务的端口(8888),然后指定了配置文件的Git仓库。配置文件的仓库可以是本地文件夹、可以是git仓库或者其他任何形式,这里以Git作为例子。
# application.yml server: port: 8888 spring: cloud: config: server: git: uri: https://github.com/chkui/spring-cloud-repo
配置好之后启动Web服务:
// chkui.spring.cloud.config.ConfigServiceApplication @EnableConfigServer //表示这是一个Configuration 服务 @SpringBootApplication public class ConfigServiceApplication { public static void main(String[] args) { SpringApplication.run(ConfigServiceApplication.class, args); } }
启动web并没有任何特别之处,像个普通的Spring Boot工程启动即可。
有了中心化服务之后自然是要使用它。也仅仅需要2步:1.配置微服务,2.启动微服务。配置内容如下:
# bootstrap.yml spring: application: name: node-config-1 cloud: config: uri: http://localhost:8888
访问中心化配置的参数主要就2个:1.指定配置文件名称、2.指定中心化服务器的地址与端口。
配置文件的名称要与 配置仓库 中的文件名对应。下面是 configuration-node-1 对应的配置文件的内容:
# https://github.com/chkui/spring-cloud-repo/blob/master/node-config-1.yml server: port: 9081 #配置node-1端口 message: Response Node Client1 With WebFlux(Netty)! #配置message参数。
下面是 configuration-node-1 中的主要代码:
package chkui.spring.cloud.config; //import 省略 @SpringBootApplication public class ConfigClientApplication1 { public static void main(String[] args) { SpringApplication.run(ConfigClientApplication1.class, args); } } @RestController class MessageRestController { //通过@Value注解获取中心化配置的参数 @Value("${message:Configuration Server Error(Node-1)}") private String message; @RequestMapping("/message") Mono<String> getMessage() { return Mono.just(this.message); } }
configuration-node-1 用spring-boot启动了一个WebFlux,这个时候访问 http://localhost:9081/message 会返回配置文件中的信息: Response Node Client1 With WebFlux(Netty)! 。
可以在不重启微服务节点的情况下更新配置参数,这在某些场景下非常意义。刷新配置参数主要是使用了 ConfigurableApplicationContext
的 refresh
接口,不过Spring Cloud整合了Actuator功能直接外部调用接口即可。
configuration-node-2 中的代码演示了这个过程:
首先需要引入 spring-boot-starter-actuator
:
dependencies { compile('org.springframework.cloud:spring-cloud-starter-config') compile('org.springframework.boot:spring-boot-starter-actuator') //引入actuator compile('org.springframework.boot:spring-boot-starter-web') }
然后在Controller层增加*@RefreshScope*注解:
@SpringBootApplication public class ConfigClientApplication2 { public static void main(String[] args) { SpringApplication.run(ConfigClientApplication2.class, args); } } @RefreshScope @RestController class MessageRestController { @Value("${message:Configuration Server Error(Node-2)}") private String message; @RequestMapping("/message") String getMessage() { return this.message; } }
最后在本地配置参数中暴露Actuator的接口:
# management: endpoints: web: exposure: include: '*'
现在就可以通过Actuator暴露的接口来更新配置参数——Post访问 localhost:9082/actuator/refresh
:
curl localhost:9082/actuator/refresh -d {} -H "Content-Type: application/json"
到了Spring Boot 2.×之后Actuator默认关闭所有Web服务接口。这里仅仅是说明有这个功能,通常不会使用Web暴露接口的方式来操作。如下图,Spring Boot和Spring Cloud已经暴露了大量的MBean,通常会使用JMX来管理和监控服务状态。
所以如果要使用 配置刷新 等功能建议使用 Spirng Boot Admin
或者其他基于JMX的管理工具来操作。
启用必要配置:
spring-cloud-config-server server.port spring.cloud.config.server.git.uri
更多配置:
spring.cloud.config.server.git.timeout
可以设置访问仓库的超时时间(秒) 。 spring.cloud.config.server.git.uri
可以使用 {application}
、 {profile}
等占位符 。用于复杂的仓库管理。 force-pull
参数可以强制更新本地仓库中的配置文件 。 spring.cloud.config.server.git.repos
参数可以用于多项配置,用子目录来区分配置。 spring.cloud.config.server.git.refreshRate
可以控制服务器到仓库的更新频率。默认为0,表示只要有微服务请求了数据就会去远程仓库获取文件。 spring.cloud.config.server.git.basedir
用于配置远程文件下载本地的临时文件夹,默认使用操作系统的 /tmp
。 spring.cloud.config.server.overrides
用于配置通用属性,通过这个配置可以让所有的节点都获取这个属性。 spring.cloud.config.server.bootstrap
和`` 嵌入别的系统中去 。 spring-cloud-starter-config
。 bootstrap.yml
设置中心化配置服务地址: spring.cloud.config.uri
。 bootstrap.yml
设置文件名: spring.application.name
。 bootstrap.yml
设置profiles: spring.profiles.active
。非必要 profile
特性,所以在仓库中具备以下命名规则: /{application}/{profile}[/{label}] /{application}-{profile}.yml /{label}/{application}-{profile}.yml /{application}-{profile}.properties /{label}/{application}-{profile}.properties