[SpringCloud第一代] Spring Cloud Config 分布式配置中⼼

一、分布式配置中⼼应⽤场景

往往,我们使⽤配置⽂件管理⼀些配置信息,⽐如application.yml

单体应⽤架构,配置信息的管理、维护并不会显得特别麻烦,⼿动操作就可以,因

为就⼀个⼯程;

微服务架构,因为我们的分布式集群环境中可能有很多个微服务,我们不可能⼀个

⼀个去修改配置然后重启⽣效,在⼀定场景下我们还需要在运⾏期间动态调整配置

信息,⽐如:根据各个微服务的负载情况,动态调整数据源连接池⼤⼩,我们希望

配置内容发⽣变化的时候,微服务可以⾃动更新。

场景总结如下:

1)集中配置管理,⼀个微服务架构中可能有成百上千个微服务,所以集中配置管理

是很重要的(⼀次修改、到处⽣效)

2)不同环境不同配置,⽐如数据源配置在不同环境(开发dev,测试test,⽣产prod)

中是不同的

3)运⾏期间可动态调整。例如,可根据各个微服务的负载情况,动态调整数据源连

接池⼤⼩等配置修改后可⾃动更新

4)如配置内容发⽣变化,微服务可以⾃动更新配置

那么,我们就需要对配置⽂件进⾏集中式管理,这也是分布式配置中⼼的作⽤。

一、Spring Cloud Confifig

1、Confifig简介

Spring Cloud Confifig是⼀个分布式配置管理⽅案,包含了 Server端和 Client端两个

部分。

Server 端:提供配置⽂件的存储、以接⼝的形式将配置⽂件的内容提供出去,通过使⽤@EnableConfifigServer注解在 Spring boot 应⽤中⾮常简单的嵌⼊ Client 端:通过接⼝获取配置数据并初始化⾃⼰的应⽤

2、Confifig分布式配置应⽤

说明:Confifig Server是集中式的配置服务,⽤于集中管理应⽤程序各个环境下的配

置。 默认使⽤Git存储配置⽂件内容,也可以SVN。

⽐如,我们要对“简历微服务”的application.yml进⾏管理(区分开发环境、测试环

境、⽣产环境)

1)登录码云,创建项⽬lagou-confifig-repo

2)上传yml配置⽂件,命名规则如下:

{application}-{profifile}.yml 或者 {application}-{profifile}.properties

其中,application为应⽤名称,profifile指的是环境(⽤于区分开发环境,测试环

境、⽣产环境等)

示例:lagou-service-resume-dev.yml、lagou-service-resume-test.yml、lagou

service-resume-prod.yml

3)构建Confifig Server统⼀配置中⼼

新建SpringBoot⼯程,引⼊依赖坐标(需要注册⾃⼰到Eureka)

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="" xmlns:xsi="" xsi:schemaLocation=" "> <parent> <artifactId>lagou-parent</artifactId> <groupId>com.lagou.edu</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>lagou-config1</artifactId> <dependencies> <!--eureka client 客户端依赖引⼊--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eurekaclient</artifactId> </dependency> <!--config配置中⼼服务端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies> </project>

配置启动类,使⽤注解@EnableConfifigServer开启配置中⼼服务器功能

package com.lagou.edu; 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 ConfigApp9006 { public static void main(String[] args) { SpringApplication.run(ConfigApp9003.class,args); } }

application.yml配置

server: port: 9006 #注册到Eureka服务中⼼ eureka: client: service-url: # 注册到集群,就把多个Eurekaserver地址使⽤逗号连接起来即可;注册到单实 例(⾮集群模式),那就写⼀个就ok defaultZone: :8761/eureka, erverB:8762/eureka instance: prefer-ip-address: true #服务实例中显示ip,⽽不是显示主机名(兼容⽼的 eureka版本) # 实例名称: 192.168.1.103:lagou-service-resume:8080,我们可以⾃定 义它 instance-id: ${spring.cloud.client.ipaddress}:${spring.application.name}:${server.port}:@project.version @ spring: application: name: lagou-service-autodeliver cloud: config: server: git: uri: #配置git服务地址 username: @.com #配置git⽤户名 password: yingdian12341 #配置git密码 search-paths: - lagou-config-repo # 读取分⽀ label: master #针对的被调⽤⽅微服务名称,不加就是全局⽣效 #lagou-service-resume: # ribbon: # NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #负载策略调整 # springboot中暴露健康检查等断点接⼝ management: endpoints: web: exposure: include: "*" # 暴露健康接⼝的细节 endpoint: health: show-details: always

测试访问::9006/master/lagou-service-resume-dev.yml,查看到

配置⽂件内容

4)构建Client客户端(在已有简历微服务基础上)

已有⼯程中添加依赖坐标

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency>

application.yml修改为bootstrap.yml配置⽂件

bootstrap.yml是系统级别的,优先级⽐application.yml⾼,应⽤启动时会检查这个

配置⽂件,在这个配置⽂件中指定配置中⼼的服务地址,会⾃动拉取所有应⽤配置

并且启⽤。

(主要是把与统⼀配置中⼼连接的配置信息放到bootstrap.yml)

注意:需要统⼀读取的配置信息,从集中配置中⼼获取

bootstrap.yml

server: port: 8080 spring: application: name: lagou-service-resume datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/lagou? useUnicode=true&characterEncoding=utf8 username: root password: jpa: database: MySQL show-sql: true hibernate: naming: physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl #避免将驼峰命名转换为下划线命名 cloud: # config客户端配置,和ConfigServer通信,并告知ConfigServer希望获取的配 置信息在哪个⽂件中 config: name: lagou-service-resume #配置⽂件名称 profile: dev #后缀名称 label: master #分⽀名称 uri: :9006 #ConfigServer配置中⼼地址 #注册到Eureka服务中⼼ eureka: client: service-url: # 注册到集群,就把多个Eurekaserver地址使⽤逗号连接起来即可;注册到单实 例(⾮集群模式),那就写⼀个就ok defaultZone: :8761/eureka, erverB:8762/eureka instance: prefer-ip-address: true #服务实例中显示ip,⽽不是显示主机名(兼容⽼的 eureka版本) # 实例名称: 192.168.1.103:lagou-service-resume:8080,我们可以⾃定 义它 instance-id: ${spring.cloud.client.ipaddress}:${spring.application.name}:${server.port}:@project.version @ # ⾃定义Eureka元数据 metadata-map: cluster: cl1 region: rn1 management: endpoints: web: exposure: include: "*"

三、Confifig配置⼿动刷新

不⽤重启微服务,只需要⼿动的做⼀些其他的操作(访问⼀个地址/refresh)刷新,

之后再访问即可

此时,客户端取到了配置中⼼的值,但当我们修改GitHub上⾯的值时,服务端

(Confifig Server)能实时获取最新的值,但客户端(Confifig Client)读的是缓存,

⽆法实时获取最新值。Spring Cloud已 经为我们解决了这个问题,那就是客户端使

⽤post去触发refresh,获取最新数据。

1)Client客户端添加依赖springboot-starter-actuator(已添加)

2)Client客户端bootstrap.yml中添加配置(暴露通信端点)

management: endpoints: web: exposure: include: refresh 也可以暴露所有的端⼝ management: endpoints: web: exposure: include: "*"

3)Client客户端使⽤到配置信息的类上添加@RefreshScope

4)⼿动向Client客户端发起POST请求,:8080/actuator/refresh,

刷新配置信息

注意:⼿动刷新⽅式避免了服务重启(流程:Git改配置—>for循环脚本⼿动刷新每

个微服务)

思考:可否使⽤⼴播机制,⼀次通知,处处⽣效,⽅便⼤范围配置刷新?

四、Confifig配置⾃动更新

在微服务架构中,我们可以结合消息总线(Bus)实现分布式配置的⾃动更新

(Spring Cloud Confifig+Spring Cloud Bus)

1、消息总线Bus

所谓消息总线Bus,即我们经常会使⽤MQ消息代理构建⼀个共⽤的Topic,通过这个

Topic连接各个微服务实例,MQ⼴播的消息会被所有在注册中⼼的微服务实例监听

和消费。换⾔之就是通过⼀个主题连接各个微服务,打通脉络

Spring Cloud Bus(基于MQ的,⽀持RabbitMq/Kafka) 是Spring Cloud中的消息

总线⽅案,Spring Cloud Confifig + Spring Cloud Bus 结合可以实现配置信息的⾃动

更新。

2、Spring Cloud Confifig+Spring Cloud Bus 实现⾃动刷新

MQ消息代理,我们还选择使⽤RabbitMQ,ConfifigServer和ConfifigClient都添加都

消息总线的⽀持以及与RabbitMq的连接信息

1)Confifig Server服务端添加消息总线⽀持

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>

2)ConfifigServer添加配置

spring: rabbitmq: host: 127.0.0.1 port: 5672 username: guest password: guest

3)微服务暴露端⼝

management: endpoints: web: exposure: include: bus-refresh 建议暴露所有的端⼝ management: endpoints: web: exposure: include: "*"

5)重启各个服务,更改配置之后,向配置中⼼服务端发送post请求

:9003/actuator/bus-refresh,各个客户端配置即可⾃动刷新

在⼴播模式下实现了⼀次请求,处处更新,如果我只想定向更新呢?

在发起刷新请求的时候:9006/actuator/bus-refresh/lagou-service

resume:8081

即为最后⾯跟上要定向刷新的实例的 服务名:端⼝号即可