Spring Cloud Config为各应用环境提供了一个中心化的外部配置。配置服务器默认采用git来存储配置信息,这样就有助于对配置进行版本管理,并且可以通过git客户端工具来方便维护配置内容。当然它也提供本地化文件系统的存储方式。
使用集中式配置管理,在配置变更时,可以通知到各应用程序,应用程序不需要重启。
创建Config Server端工程config-server:
File -> New->Product... -> 选择Spring Initializr -> Project SDK用1.8 -> Next -> 输入Product Metadata -> Next
(springboot选择2.0以上) 选择Cloud Discovery -> 选择Eureka Discovery 选择Cloud Config -> 选择Config Server
由于选择了Eureka Discovery和Config Server,创建成功后pom.xml里已经帮你引入了以下依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
Config Server也是要注册到Eureka,作为Eureka Client,我们还要加入如下依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 避免后面的数据库配置出错,mysql依赖也加了 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
再给启动类加上注解@EnableDiscoveryClient和@EnableConfigServer:
package com.hicoview.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; @SpringBootApplication @EnableDiscoveryClient @EnableConfigServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class, args); } }
配置application.yml:
eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ spring: application: name: config cloud: config: server: git: uri: http://code.hicoview.com:8000/backend/config.git username: root password: 8ggf9afd6g9gj # 配置文件下载后存储的本地目录 basedir: /Users/zhutx/springcloud/config/basedir server: port: 9999
然后按照配置的git仓库地址,在github或gitlab上创建config仓库。
以商品微服务的配置来演示,在config仓库创建product-dev.yml:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.jdbc.Driver username: root password: passwd_1986 url: jdbc:mysql://127.0.0.1:3306/SpringCloud_Sell?characterEncoding=utf-8&useSSL=false
启动作为Config Server的config-server工程,查看 http://localhost:8761 :
访问配置服务端的以下任意地址,都可以显示出对应格式的配置内容:
http://localhost:9999/product-dev.yml
http://localhost:9999/product-dev.properties
http://localhost:9999/product-dev.json
可见,Config Server获取到了远程git仓库上的配置,并将其作为自身的REST服务提供了出去。
接下来我们看看配置客户端Config Client(即product-server)怎么引用配置。
我们给product-server加入配置客户端的依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency>
修改application.yml配置:
spring: application: name: product cloud: config: discovery: enabled: true service-id: CONFIG profile: dev eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
这样子就可以从Eureka服务注册中心找到CONFIG服务,并拿到product-dev.yml了。
启动product-server,查看eureka注册中心,CONFIG这个Config Server服务已经注册上去了:
如果代码里有操作数据库,那么启动其实会出错,因为spring boot不知道配置加载顺序。
我们期望先拿到CONFIG的配置,再初始化数据库。
解决办法是把product-server的application.yml改成bootstrap.yml就好。
微服务工程使用配置服务的情况下,注意将application.yml都改成bootstrap.yml。并且,让bootstrap.yml文件只保留Eureka配置和获取Config Server服务的配置;
另外,如果生产环境要使用统一配置中心,可以启动多个Config Server进程,保持高可用。
同样的操作,把order-server配置也抽取到外部
下图是当前的配置工作机制,config-server拉取远端git配置,并在本地存一份。然后config-server通过把自身注册到Eureka从而提供了拉取配置的服务,而配置客户端(product和order)通过引入config-client依赖,在启动时便能获取加载到了配置。
我们需要做到修改远程配置,应用程序不重启,还需要借助Spring Cloud Bus。Spring Cloud Bus集成了MQ,并为config-server提供了这个配置刷新服务(bus-refresh)。
如下图所示,做法是远端git修改配置后,通过webhook调用config-server的/bus-refresh服务,发布RabbitMQ消息,config-client接收消息并更新配置。
我们先安装RabbitMQ:
# docker安装rabbitmq docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.7.9-management # 验证下 docker ps | grep 'rabbitmq'
能成功访问RabbitMQ控制台 http://localhost:15671 ,继续。
修改Config Server端,增加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
修改application.yml,增加以下配置,把包括bus-refresh在内的所有config server的服务都暴露出来:
management: endpoints: web: exposure: include: "*"
我们拿product-server来演示,修改product-server的pom增加依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
然后提供一个接口,方便我们在配置变验证结果:
@RestController @RequestMapping("/env") @RefreshScope public class EnvController { @Value("${env}") private String env; @GetMapping("/print") public String print() { return env; } }
测试下,我们修改远端git配置,先增加env配置:
server: port: 8080 spring: datasource: driver-class-name: com.mysql.jdbc.Driver username: root password: passwd_1986 url: jdbc:mysql://127.0.0.1:3306/SpringCloud_Sell?characterEncoding=utf-8&useSSL=false # 增加了该配置 env: dev
重启下config-server和product-server。
访问 product-server http://localhost:8080/env/print ,显示dev
然后我们把远端env配置项改成test
调用config-server的配置刷新服务 bus-refresh:
curl -v -X POST http://localhost:9999/actuator/bus-refresh
再次访问 product-server http://localhost:8080/env/print ,显示test
至此,已经做到了变更配置不重启应用。我们再借助Git仓库的webhook功能,在push指令发生后帮我们发个bus-refresh请求就完美了。Gitlab的话在仓库的这个位置:
Repository -> Settings -> Integrations -> Add webhook