
一、前言随着业务的扩展为了方便开发和维护项目我们通常会将大项目拆分成多个小项目做成微服务每个微服务都会有各自配置文件管理和修改文件起来也会变得繁琐。而且当我们需要修改正在运行的项目的配置时通常需要重启项目后配置才能生效。上述的问题将是本篇需要解决的问题。二、介绍2.1 简单介绍Spring Cloud Config 用于为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持它分为服务端和客户端两部分。服务端config server也称为分布式配置中心是一个独立的微服务应用用来连接配置仓库并为客户端提供获取配置信息加密/解密信息等访问接口。而客户端config client则是微服务架构中各微服务应用或基础设施通过指定的配置中心来管理应用资源与业务相关的配置内容并在启动的时候从配置中心获取和加载配置信息。2.2 运行原理如上图当 Config Client 首次启动时会向 Config Server 获取配置信息Config Server 接收到请求再从远程私有仓库获取配置连接不上项目会报错并保存到本地仓库中。当 Config Client 再次启动时会向 Config Server 获取配置信息Config Server 还是会先从远程私有仓库拉去数据。如果网络问题或认证问题导致无法连接远程私有库Config Server 才会从本地仓库获取配置信息返回给 Config Client。三、Config 实战本次实战基于 Eureka 篇的项目进行扩展演练。不清楚的读者请先转移至 《Spring Cloud Eureka服务治理》 进行浏览。我们使用配置中心来维护 order-server 的配置数据(application.yml)。测试场景由于配置中心服务本身也是一个微服务因此我们需要将配置中心注册到 Eureka 上当 order-server 启动时先向 Eureka 获取配置中心的访问地址然后从配置中心获取相应的配置信息进行正常启动。本篇实战用到的项目列表项目服务实例实例id端口描述eureka-serverEureka-Servereureka-server19001注册中心Eureka 服务端eureka-serverEureka-Servereureka-server29002注册中心Eureka 服务端config-serverConfig-Serverconfig-server8500配置中心Eureka 客户端、Config 服务端config-clientConfig-Clientconfig-client10001配置客户端Eureka 客户端、Config 客户端3.1 新建私有仓库在 GitHub 上新建一个私有仓库名为 cloud-config。我们将 order-server 项目的配置文件放到改仓库中如下图新建 3 个 yml 文件内容为config-client-dev.ymlserver:port:10001eureka:instance:instance-id:config-clientprefer-ip-address:off# 访问路径可以显示 IPenv:devconfig-client-pro.ymlserver:port:10001eureka:instance:instance-id:config-clientprefer-ip-address:off# 访问路径可以显示 IPenv:proconfig-client-test.ymlserver:port:10001eureka:instance:instance-id:config-clientprefer-ip-address:off# 访问路径可以显示 IPenv:test3.2 config 服务端新建一个 spring boot 项目名为 config-server任意名字。3.2.1 添加依赖dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-config-server/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependency3.2.2 application.ymlserver:port:8500spring:application:name:Config-Servercloud:config:server:git:uri:https://github.com/wno704/cloud-config.git#配置了Git仓库的地址这里用的是码云当然你也可以使用别的Git代码托管平台username:(您的帐号)password:(您的密码)basedir:E:\workspace\workspace(idea)\spring\cloud\config-server\src\main\data# 本地库目录label:mastereureka:instance:instance-id:config-serverprefer-ip-address:offclient:register-with-eureka:true# 是否向注册中心注册自己fetch-registry:true# 是否检索服务service-url:#defaultZone: http://127.0.0.1:8761/eureka/defaultZone:http://eureka01:9001/eureka/,http://eureka02:9002/eureka/3.2.3 启动类添加 EnableConfigServerEnableConfigServerEnableEurekaClientSpringBootApplicationpublicclassConfigServerApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ConfigServerApplication.class,args);}}启动成功后我们在idea的http工具中访问http://localhost:8500/config-client-test.ymlconfig-server 服务成功拉去远程私有仓库的配置数据。其中访问规则如下IP:PORT/{name}-{profiles}.yml IP:PORT/{label}/{name}-{profiles}.ymlname文件名可当作服务名称profiles: 环境如devtestprolable: 分支指定访问某分支下的配置文件默认拉去 master 分支。3.3 config 客户端在 config-client 项目中。3.3.1 添加依赖dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-config/artifactId/dependencydependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-eureka-client/artifactId/dependency3.3.2 新建 bootstrap.yml删除 application.yml并新建 bootstrap.yml保存如下内容spring:application:name:Config-Clientcloud:config:discovery:enabled:trueservice-id:Config-Serverprofile:devlabel:mastereureka:instance:instance-id:config-clientprefer-ip-address:offclient:register-with-eureka:true# 是否向注册中心注册自己fetch-registry:true# 是否检索服务service-url:defaultZone:http://eureka01:9001/eureka/,http://eureka02:9002/eureka/配置中通过 spring.cloud.config.discovery.service-id 确定配置中心再通过 spring.application.name 的值拼接 spring.cloud.config.profile 的值从而确定需要拉去从配置中心获取的配置文件。如config-client-dev注意必须保留 eureka 注册中心的配置否则 config-client 无法连接注册中心也就无法获取配置中心(config-server)的访问信息。3.3.3 测试新建一个测试类RestControllerRequestMapping(/test)publicclassTestController{Value(${env})privateStringenv;// 从配置中心获取RequestMapping(/getConfigInfo)publicStringgetConfigInfo(){returnenv;}}启动成功后我们在idea的http工具中访问http://localhost:10001/test/getConfigInfo成功获取 config-server 从远程私有仓库拉去的数据由于在 bootstrap.yml 中配置了 spring.cloud.config.profiledev因此拉取到的数据就是 config-client-dev.yml 中的数据。四、Config-Server额外配置上面我们简单的地搭建了一个Config-Server下面我们来进一步了解Config-Server的可用配置。4.1 占位符的使用在Config-Server中除了固定配置一个Git仓库地址外我们也可以使用占位符来灵活的指定Git仓库地址。将上面Config-Server的Git仓库地址改为spring:cloud:config:server:git:uri:https://github.com/wno704/{application}这里使用占位符{application}来代替上面的cloud-config通过这种配置我们可以让不同的Config-Client去不同的Git仓库获取配置。比如当Config-Client的项目名称为order的时候对应Git仓库地址为:https://github.com/wno704/order当名称为test时对应Git仓库地址为:https://github.com/wno704/test。这样我们就可以为不同的项目配置不同的Git仓库。4.2 子目录支持除了使用占位符为每个项目创建单独的Git仓库来存储配置信息外我们也可以只创建一个Git仓库来存储配置只不过是将不同的项目配置放置到不同的目录下只需要像下面这样配置即可spring:cloud:config:server:git:uri:https://github.com/wno704/cloud-config/username:xxxxpassword:xxxxsearch-paths:{application}通过上面的配置我们可以实现在https://github.com/wno704/cloud-config/仓库中一个Config-Client对应一个配置目录的效果即当Config-Client的项目名称为order的时候其搜索配置的目录为https://github.com/wno704/cloud-config/order。注意:这里search-paths的占位符必须加上单引号’否则没办法正确读取配置。4.3 clone-on-start默认情况下Config-Server在启动的时候并不会马上就去Git参考clone配置文件只有当Config-Clinet从Config-Server获取相关配置信息的时候其才会去进行clone操作。我们可以将clone-on-start属性设置为true其Config-Server在启动的时候就进行clone操作spring:cloud:config:server:git:clone-on-start:true这样做的好处在于当Git连接信息有误时可以马上发现。4.4 整合Spring SecurityConfig-Server中包含了Git连接信息为了使其更加安全我们可以通过Spring Security来做用户名密码认证。在Config-Server中加入Spring Security依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId/dependency然后在Config-Server的配置文件application.yml中加入用户名和密码spring:security:user:name:wno704password:xxxxxx与此同时我们也需要在Config-Client中配置Config-Server的用户名和密码否则在获取配置的时候将报401错误spring:cloud:config:username:wno704password:xxxxxx五、Config-Client额外配置5.1 刷新配置在Config-Server和Config-Client都启动后如果这时候Git仓库存储的配置信息改变了在不重启Config-Client的情况下配置信息是不会跟着更新的。那么如何在Git仓库存储的配置得到改变的时候也刷新Config-Client中获取到的配置值呢很简单我们只需要对Config-Client进行简单的改造5.1.1 增加依赖在Config-Client中添加spring-boot-starter-actuator依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency该依赖包含了/refresh端点可以用来刷新配置。5.1.2 加入RefreshScope然后在获取配置的Controller上加入RefreshScope注解RefreshScopeRestControllerRequestMapping(/test)publicclassTestController{Value(${env})privateStringenv;// 从配置中心获取RequestMapping(/getConfigInfo)publicStringgetConfigInfo(){returnenv;}}5.1.3 关闭认证值得注意的是我们需要在Config-Client的配置文件中加入如下配置来关闭认证否则我们无权访问/refresh端点management:endpoints:web:exposure:include:refreshspringboot2.0.3.RELEASE版本以下配置如下management:security:enabled:false5.1.4 验证重启Config-Client访问http://localhost:10001/test/getConfigInfo这时候我们将Git仓库中对应的配置信息改为“测试配置刷新”再次访问http://localhost:10001/test/getConfigInfo会发现值还是dev。git配置webhooks,URL为http://localhost:10001/refresh接着我们使用以下命令来刷新配置curl -X POST http://localhost:10001/actuator/refresh这时候再次访问http://localhost:10001/test/getConfigInfo可看到在不重启Config-Client的前提下配置值已经得到了更新。