若是微服务架构中没有使用统一配置中心时,所存在的问题:java
在SpringCloud中咱们使用config组件来做为统一配置中心:git
废话很少说,本小节咱们来开发统一配置中心的server端,在IDEA中新建一个Spring Initializr项目,并选择相应的模块:web
项目的pom.xml文件配置的依赖以下:spring
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-monitor</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies>
由于config server是须要到git上拉取配置文件的,因此还须要在远程的git上新建一个存放配置文件的仓库,我这里使用的是码云:docker
建立好后,新建一个文件,而后把订单服务的配置文件内容粘贴进来:json
注:我这里事先已经存在一个商品服务和订单服务bootstrap
回到config项目中,编辑application.yml配置文件内容以下:浏览器
spring: application: name: config cloud: config: server: git: uri: https://gitee.com/Zero-One/config-repo # 远程git仓库的地址 username: username # 以及相应的帐户名 password: password # 和密码 basedir: E:\Java_IDEA\config\basedir # 可使用这个配置项来指定本地git仓库的路径 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ server: port: 8974
在启动类上,加上@EnableConfigServer
注解,声明这是一个config-server。代码以下:安全
package org.zero.springcloud.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient @EnableConfigServer public class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); } }
启动项目,访问以下地址,能够看到可以访问到配置文件的内容:bash
若是访问.properties格式的,还会自动进行转换:
.json格式的也可以进行转换:
注:若是配置文件的内容格式有问题的话,访问会报500错误。咱们能够利用这个特性,来检查咱们的配置文件是否正确
在上图访问的地址中能够发现,访问的配置文件名后面还有一个-a,这实际上是config的访问规则。后面必需要跟个-xxx,因此在建立文件的时候,最好是按这种命名规则来建立。配置文件的访问规则以下:
/{name}-{profiles}.yml /{label}/{name}-{profiles}.yml name : 文件名,通常以服务名来命名 profiles : 通常做为环境标识 lable : 分支(branch),指定访问某分支下的配置文件
有一点值得注意的是,若是有两个前缀名相同文件,例如一个order.yml,一个order-dev.yml。那么在访问相同前缀的文件时,config-server会对这两个文件进行一个合并。例如order.yml有一段配置是order-dev.yml没有的,理应访问order-dev.yml的时候是没有那段配置的,但访问的结果倒是它俩合并以后的内容,即order-dev.yml会拥有order.yml里所配置的内容。
除此以外还有一点就是,随着后期微服务数量的增长,配置文件的数量天然也会随着增长,并且实际的企业项目中都会在不一样的部署环境使用不一样的配置文件,例如开发环境(dev)、测试环境(test)、生产环境(product)等。因此一个服务至少会有三个以上的配置文件,若是咱们将这些配置文件直接放在git仓库的根目录下的话,就会显得很杂乱,不便于查看、修改。以下示例:
这时咱们很天然的会想到将不一样服务的配置文件放到以服务名命名的目录下,例如:
这样感受就好多了,想找哪一个服务的配置文件直接去相应的目录下找就能够了。可是当你开开心心的将配置文件整理到一个个的目录里并重启了config server后,就会发现这些配置文件全都加载不到了。这是由于config server默认状况下只会搜索git仓库根路径下的配置文件,因此咱们还须要加上一个配置项:search-paths,该配置项用于指定config server搜索哪些路径下的配置文件,须要注意的是这个路径是相对于git仓库的,并不是是项目的路径。以下示例:
spring: application: name: config cloud: config: server: git: ... search-paths: /** # 指定搜索根路径下的全部目录,如有多个路径使用逗号隔开
在上一小节中,咱们介绍了config-server的使用以及配置文件的访问规则,本小节将介绍config-client端的使用,咱们以订单服务为例。
在订单服务工程的pom.xml文件中,增长以下依赖配置:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-client</artifactId> </dependency>
注:商品服务工程中也增长这个依赖,这样两个服务均可以从config-server中读取配置了
而后将application.yml重命名为bootstrap.yml,并修改内容以下:
spring: application: name: order cloud: config: discovery: enabled: true service-id: CONFIG # 注册中心的服务名 profile: dev # 指定配置文件的环境
注:之因此要用bootstrap.yml,是由于启动SpringBoot项目时,会优先读取bootstrap.yml里的配置,而后才会读取application.yml。若是不经过bootstrap.yml里的配置,先从配置中心拉下相应的配置文件,就会报错
重启项目,使用建立订单接口,测试一下是否正常:
统一配置中心和服务注册中心同样,都是须要高可用的,否则配置文件都没有的话,项目天然无法跑起来了。因此咱们来看看如何使config-server可以高可用。
config-server也属因而一个微服务,因此让其高可用很简单,只须要启动多个服务实例便可。首先咱们来复制几个config-server的实例,跑在不一样的端口上:
启动后,到eureka上能够看到也都注册成功了,这样咱们就有了三个config-server实例:
其余服务经过负载均衡策略,就可以调用这几个config-server实例,轻松实现高可用
还有一个须要注意的点是服务注册中心地址端口的问题,咱们都知道eureka-server的默认端口是8761,若是咱们如今将eureka-server的端口改为8762,那么订单服务就会启动不了。由于在bootstrap.yml配置文件中,并无配置eureka-server的地址。
项目启动的时候会优先读取bootstrap.yml,按照配置的内容去配置中心拉取配置文件,可是在此以前订单服务须要先去注册中心上找配置中心的调用地址,若是eureka-server端口更改了的话,就会访问不到配置中心,天然也就没法调用配置中心拉取配置文件了,如今咱们之因此能够访问是由于SpringBoot默认访问的是本地的8761端口。
因此咱们须要修改远程git仓库上的配置文件内容以下:
而后在bootstrap.yml中增长eureka-server的配置才对:
eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
这也是一个小细节,若是没有注意的话,容易掉进这个坑。
在上两个小节中,咱们学习了统一配置中心的server端以及client端的使用,也成功拉取了相应的配置文件。可是这样仍然不够,由于还不能作到自动刷新配置文件,例如我在git上更改了配置文件,还须要重启服务才可以读取到最新的配置。因此本小节将介绍一下如何使用Spring Cloud Bus实现自动刷新配置,Bus在这里是总线的意思。
示意图:
Spring Cloud Bus会向外提供一个http接口,即图中的/actuator/bus-refresh。咱们将这个接口配置到远程的git上,当git上的文件内容发生变更时,就会自动调用/bus-refresh接口。Bus就会通知config-server,config-server会发布更新消息到消息队列中,其余服务订阅到该消息就会信息刷新,从而实现整个微服务进行自动刷新。
因为实现配置自动刷新,须要用到消息中间件,因此还得安装,我这里使用RabbitMQ。而且是在CentOS上使用docker进行安装,docker的版本以下:
[root@01server ~]# docker info |grep "Server Version" Server Version: 18.03.1-ce [root@01server ~]#
安装并启动rabbitmq:
[root@01server ~]# docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.7.3-management ... [root@01server ~]#
进入容器里,添加超级管理员用户:
[root@01server ~]# docker exec -it 1ca60f11d6d9 bash # 进入容器 root@my-rabbit:/# rabbitmqctl add_user admin password # 添加用户,用户名为admin,密码为password Adding user "admin" ... root@my-rabbit:/# rabbitmqctl set_user_tags admin administrator # 设置用户权限为超级管理员 Setting tags for user "admin" to [administrator] ... root@my-rabbit:/# rabbitmqctl set_permissions -p /${user_name} admin '.*' '.*' '.*' # 设置远程登陆权限 root@my-rabbit:/#
若是你的系统防火墙没有关闭的话,还须要开放相应的端口:
[root@01server ~]# firewall-cmd --zone=public --add-port=15672/tcp --permanent success [root@01server ~]# firewall-cmd --zone=public --add-port=5672/tcp --permanent success [root@01server ~]# firewall-cmd --reload success [root@01server ~]#
使用浏览器访问${ip}:15672
,进入登陆界面:
登陆以后才能进入到管理页面:
安装好RabbitMQ后,咱们就能够着手实现配置的刷新了。首先咱们须要在config项目中,增长Spring Cloud Bus依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
注:商品服务以及订单服务也须要加入这个依赖
而后在配置文件中,配置rabbitmq的地址以及用户密码,修改config服务的配置以下:
spring: application: name: config cloud: config: server: git: uri: https://gitee.com/Zero-One/config-repo username: username password: password basedir: E:\Java_IDEA\config\basedir # 配置rabbitmq的地址以及用户密码 rabbitmq: host: 192.168.190.129 port: 5672 username: admin password: admin eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ # 容许/actuator/bus-refresh接口被外部调用 management: endpoints: web: exposure: include: "*"
修改商品服务的配置以下:
spring: application: name: product cloud: config: discovery: enabled: true service-id: CONFIG profile: dev rabbitmq: host: 192.168.190.129 port: 5672 username: admin password: admin eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
修改订单服务的配置以下:
spring: application: name: order cloud: config: discovery: enabled: true service-id: CONFIG profile: dev rabbitmq: host: 192.168.190.129 port: 5672 username: admin password: admin eureka: client: service-url: defaultZone: http://localhost:8761/eureka/
配置好后,将以上项目都重启,而后到RabbitMQ上,能够看到注册上来的队列:
确认都可以正常注册到rabbitmq后,咱们到码云上,规范配置文件的名称。修改以前的order.yml为order-dev.yml,而且增长商品服务的配置文件,以下:
并在order-dev.yml文件里,增长一段env配置:
完成配置文件的修改后,再到订单服务项目里,增长一个 EnvController 类,用来测试配置刷新是否正常。代码以下:
package org.zero.springcloud.order.server.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @program: sell_order * @description: * @author: 01 * @create: 2018-08-20 23:17 **/ @RestController @RequestMapping("/env") @RefreshScope // 这个注解声明了刷新配置的范围,若是使用config配置类的话,就声明到配置类上便可 public class EnvController { @Value("${env}") private String env; @GetMapping("/print") public String print(){ return env; } }
重启订单服务项目,访问/env/print
接口,返回的结果以下:
这时,咱们再到码云上修改order-dev.yml文件里的env配置为beat,以下:
而后访问bus用于刷新配置的接口:
稍等一会,控制台应该会打印刷新日志,接着再访问以前的测试接口,返回beta则说明刷新是有效的。由于这个过程当中,咱们并无重启订单服务或配置中心服务:
到了本小节,就表明咱们已经成功集成了RabbitMQ以及Spring Cloud Bus进行配置文件的动态刷新,可是咱们目前依旧须要手动去访问Bus用于刷新配置的接口,才能完成配置文件的动态刷新。咱们但愿的是,当git仓库的文件更新时就可以实现动态刷新配置文件。要实现这个功能就须要Git仓库可以在配置文件更新后,自动调用Bus用于刷新配置的接口。那么要怎么实现这个功能呢?这就须要用到WebHooks了,好在码云和GitHub都支持WebHooks,咱们只须要配置一下接口地址便可。这也是咱们本小节须要演示的。
注:SpringCloud须要2.0.0以上的版本才开始支持码云的WebHooks,低版本对码云的WebHooks不兼容
首先打开仓库的管理界面,选择WebHooks,并点击右上角的添加:
而后输入相应的配置信息,注意这里不是配置/actuator/bus-refresh
接口了 ,而是配置 spring cloud config 里特定给WebHooks调用的/monitor
接口。至于域名,我这里使用了内网穿透的地址:
添加完成后,点击右上角的测试,返回结果以下,则表明测试经过:
如今咱们用以前的order-dev.yml配置文件进行一个测试,把env的值改成test,以下:
而后在不重启任何项目的状况下,访问以前打印env配置的接口。返回结果以下表明自定刷新成功了: