1 Spring Cloud Config 简介

配置文件想必大家都不陌生。在Spring Boot项目中,默认会提供一个application.properties或者application.yml文件,我们可以把一些全局性的配置或者需要动态维护的配置写入改文件,例如数据库连接,功能开关,限流阈值,服务地址等。为了解决不同环境下服务连接配置等信息的差异,Spring Boot还提供了基于spring.profiles.active={profile}的机制来实现不同的环境的切换。
随着单体架构向微服务架构的演进,各个应用自己独立维护本地配置文件的方式开始显露出它的不足之处。主要有下面几点。

  • 配置的动态更新:在实际应用会有动态更新位置的需求,比如修改服务连接地址、限流配置等。在传统模式下,需要手动修改配置文件并且重启应用才能生效,这种方式效率太低,重启也会导致服务暂时不可用。
  • 配置多节点维护:在微服务架构中某些核心服务为了保证高性能会部署上百个节点,如果在每个节点中都维护一个配置文件,一旦配置文件中的某个属性需要修改,可想而知,工作量是巨大的。
  • 不同部署环境下配置的管理:前面提到通过profile机制来管理不同环境下的配置,这种方式对于日常维护来说也比较繁琐。

统一配置管理就是弥补上述不足的方法,简单说,最近本的方法是把各个应用系统中的某些配置放在一个第三方中间件上进行统一维护。然后,对于统一配置中心上的数据的变更需要推送到相应的服务节点实现动态跟新,所以微服务架构中,配置中心也是一个核心组件,而Spring Cloud Config就是一个配置中心组件,并且可以Git,SVN,本地文件等作为存储。如下图所示。
image.png
Spring Cloud Config架构

2 个人记账项目spring cloud config实战

1.创建新的项目

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.4.9</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.csz</groupId>
  12. <artifactId>bill-config</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>bill-config</name>
  15. <description>bill-config</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. <spring-cloud.version>2020.0.3</spring-cloud.version>
  19. </properties>
  20. <dependencies>
  21. <dependency>
  22. <groupId>org.springframework.cloud</groupId>
  23. <artifactId>spring-cloud-config-server</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.projectlombok</groupId>
  27. <artifactId>lombok</artifactId>
  28. <optional>true</optional>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-test</artifactId>
  33. <scope>test</scope>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.cloud</groupId>
  37. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  38. </dependency>
  39. </dependencies>
  40. <dependencyManagement>
  41. <dependencies>
  42. <dependency>
  43. <groupId>org.springframework.cloud</groupId>
  44. <artifactId>spring-cloud-dependencies</artifactId>
  45. <version>${spring-cloud.version}</version>
  46. <type>pom</type>
  47. <scope>import</scope>
  48. </dependency>
  49. </dependencies>
  50. </dependencyManagement>
  51. <build>
  52. <plugins>
  53. <plugin>
  54. <groupId>org.springframework.boot</groupId>
  55. <artifactId>spring-boot-maven-plugin</artifactId>
  56. <configuration>
  57. <excludes>
  58. <exclude>
  59. <groupId>org.projectlombok</groupId>
  60. <artifactId>lombok</artifactId>
  61. </exclude>
  62. </excludes>
  63. </configuration>
  64. </plugin>
  65. </plugins>
  66. </build>
  67. </project>

2.启动类 添加@EnableConfigServer注解表示这个时configServer类

  1. package com.csz.billconfig;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.cloud.config.server.EnableConfigServer;
  5. @SpringBootApplication
  6. @EnableConfigServer
  7. public class BillConfigApplication {
  8. public static void main(String[] args) {
  9. SpringApplication.run(BillConfigApplication.class, args);
  10. }
  11. }

3.配置文件

  1. server:
  2. port: 9006
  3. spring:
  4. application:
  5. name: bill-config
  6. cloud:
  7. config:
  8. server:
  9. git:
  10. uri: https://gitee.com/tyson-chai/bill-config.git
  11. search-paths: config
  12. default-label: master
  13. eureka:
  14. client:
  15. service-url:
  16. defaultZone: http://127.0.0.1:9004/eureka

Config Server默认存储配置的方式是git,如果git仓库是公开仓库,username和password属性可以省略不配置,具体配置属性解释如下。

  • spring.cloud.config.server.git.uri:配置文件所在的git仓库
  • spring.cloud.config.server.git.search-paths:配置文件所在目录
  • spring.cloud.config.server.git.default-label:配置文件分支

在git仓库https://gitee.com/tyson-chai/bill-config.git中,创建config目录,在config目录中创建bill-config-dev.yml配置文件,代码如下。

  1. #mysql数据库连接池
  2. spring:
  3. datasource:
  4. driver-class-name: com.mysql.jdbc.Driver
  5. url: jdbc:mysql://localhost:3306/bill-manager?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
  6. username: root
  7. password: csz981027
  8. thymeleaf:
  9. cache: false #关闭thymeleaf缓存
  10. application:
  11. name: bill-manager
  12. #mybatis
  13. mybatis:
  14. type-aliases-package: com.csz.pojo #别名搜索
  15. mapper-locations: classpath:/mybatis/*.xml
  16. server:
  17. port: 9001
  18. eureka:
  19. client:
  20. service-url:
  21. defaultZone: http://127.0.0.1:9004/eureka
  22. fetch-registry: true
  23. register-with-eureka: true

先打开eureka在打开config服务。在网址上输入http://localhost:9006/bill-config-dev.yml
image.png

3 改造bill-manger服务,使用远程调用的方式

1.引入 配置

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-config</artifactId>
  4. </dependency>

2.修改配置文件

  1. spring:
  2. application:
  3. name: bill-manager
  4. cloud:
  5. config:
  6. uri: http://localhost:9006
  7. profile: default
  8. label: master
  9. config:
  10. import: optional:configserver:http://localhost:9006

在配置中,我们只配置了bill-manager这个服务去哪里调用我们git上的配置文件

  • spring.config.import=optional:configserver:http://localhost:9006,指定Spring Boot项目从Config Server导入配置
  • spring.cloud.config.url:Config Server地址,默认localhost:8888
  • spring.cloud.config.profile:为git配置文件的后缀
  • spring.cloud.config.label:为访问git的分支。

而且我们没有设置原来的端口号为9001,默认的就是8080,如果我们启动所有的服务,在网址上输入http://localhost:9001/bill/list-page 就说明已经读取到了远程的配置文件,且在服务启动的时候 已经显示地址为9001.
3-2结果.png

4 使用rabbitmq自动刷新配置文件

首先安装rabbitmq环境。本次使用windows安装环境。具体参考:
https://blog.csdn.net/tirster/article/details/121938987
Spring Cloud Config在项目启动时自动加载配置内容这一机制,导致了他的一个缺陷,配置不能自动刷新,在上述案例中,修改git仓库中的key1的值”key1=v11”,发现支付服务得到的配置项key1的值还是旧的配置内容,新的内容不会自动刷新过来,在微服务架构中,动辄上百个节点如果都需要重启,这个问题非常麻烦。
我们可以使用Spring Cloud Bus和Spring Boot Actuator实现自动刷新

image.png

4.1.在bill-config服务中添加如下依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-bus-amqp</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-actuator</artifactId>
  8. </dependency>

在application.yml中配置连接RabbitMQ,同时配置暴露/actuator/bus-refresh端点,代码如下。

  1. server:
  2. port: 9006
  3. spring:
  4. application:
  5. name: bill-config
  6. cloud:
  7. config:
  8. server:
  9. git:
  10. uri: https://gitee.com/tyson-chai/bill-config.git
  11. search-paths: config
  12. default-label: master
  13. rabbitmq:
  14. port: 15672
  15. username: guest
  16. password: guest
  17. management:
  18. endpoints:
  19. web:
  20. exposure:
  21. include: bus-refresh
  22. endpoint:
  23. bus-refresh:
  24. enabled: true
  25. eureka:
  26. client:
  27. service-url:
  28. defaultZone: http://127.0.0.1:9004/eureka

4.2.在bill-manger服务中添加如下依赖 作为监听rabbitmq的组件

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-starter-bus-amqp</artifactId>
  4. </dependency>

同时配置她的yml文件,配置rabbitmq相关的连接操作

  1. rabbitmq:
  2. port: 15672
  3. username: guest
  4. password: guest

4.3使用@RefreshScope注解刷新更改的配置,测试代码如下。

  1. package com.csz.controller;
  2. import com.csz.pojo.Bill;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.cloud.context.config.annotation.RefreshScope;
  6. import org.springframework.http.ResponseEntity;
  7. import org.springframework.web.bind.annotation.PathVariable;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. @Slf4j
  10. @RefreshScope
  11. @RequestMapping("/bill")
  12. public class TestController {
  13. @Value("${key1}")
  14. private String key1;
  15. @Value("${key2}")
  16. private String key2;
  17. @Value("${key3}")
  18. private String key3;
  19. @RequestMapping("/{id}")
  20. public ResponseEntity<Bill> payment(@PathVariable("id") Integer id) {
  21. log.info("key1={}, key2={}, key3={}", key1, key2, key3);
  22. Bill bill = new Bill();
  23. return ResponseEntity.ok(bill);
  24. }
  25. }

image.png
在远程仓库将key1的值修改为v11
并通过postman发送post请求http://localhost:9006/actuator/busrefresh 返回结果204
image.png
返回结果为:
image.png