SpringCloud第十章,升级篇,服务网关GateWay、服务配置Config和服务总线Bus
一、服务网关GateWay
1、网关概述
为什么存在:
- 不同的微服务一般会有不同的网络地址,而外部的客户端可能需要调用多个微服务的接口才能完成一个业务的需求,如果让客
- 户端和多个微服务直接通信,会产生很多问题:
- a、客户端多次请求不同的微服务,增加客户端的复杂性
- b、存在跨域请求,在一定场景下处理困难
- c、认证复杂,每个微服务都需要独立的认证
- d、难以重构,随着项目的迭代,可能需要重新划分微服务。
- 例如:可能会将多个微服务合并成一个或者将一个微服务拆分成多个微服务。这是如果客户端直接与各微服务间通信,增加重构的难度。
- e、某些微服务可能使用了防火墙或者浏览器的不友好协议,直接访问会有一定的困难。
复制代码 什么是服务网关:
- 网关是介于客户端和服务端之间的中间层。所有的外部请求都会经过网关这一层。也就是说API实现方面更多的考虑业务逻辑。而安全、性能、监控可以交友网关来做。这样既提高了业务的灵活性又不失安全性。
复制代码
有什么长处:
- a、安全,只有网关系统对外进行暴露,微服务可以隐藏在内网,通过防火墙保护。
- b、易于监控,可以在网关收集监控数据推送到外部系统进行监控。
- c、易与认证,可以在网关上进行认证,然后再将请求转发到后端的微服务,无需再每个微服务上进行认证。
- d、减少了客户端和各微服务之间的交互次数。
- e、易于统一鉴权。验证用户是否具有访问各微服务的权利。
复制代码 2、什么是GateWay
是什么:
- 一句话:gateway是zuul1.x版的替代。
- springcloud gateway旨在为微服务架构提供一种简单有效的统一的API路由管理方式。并且基于filter链的方式提供网关的基本功能:安全、监控、熔断、限流、重试等。
复制代码 能干什么
gateway和zuul1.x的区别:
- zuul1.x是基于servlet之上的一个阻塞式处理模型。
- gateway是非阻塞式的。
复制代码 3、核心概念
- a、断言predicate:
- 参考java8的predicate,开发人员可以匹配http请求中的所有内容。如果请求和路由相匹配则进行路由。
- b、过滤Filter:
- 指的是spring框架中springGateway的实例,可以对请求在路由前或之后进行修改。
- c、路由Route:
- 路由是构建网关的基本模块,它由ID、目标URI、一系列断言predicate和过滤器filter组成。如果断言为true则匹配该路由。
- web请求通过一些匹配条件,定位到真正的服务节点,并在这个转发的过程前后进行一系列的精细化控制。
- predicate就是我们的匹配条件,而filter,就可以理解为一个无所不能的拦截器,有了这两个元素再加上一个uri就可以实现一个具体的路由了。
复制代码 4、gateway工作流程
- 客户端向springcloud gateway发出请求,然后在gateway handler mapping中找到与请求相匹配的路由,将其发送到gateway web handler.
- handler再通过指定的过滤器链来将请求发送到实际服务执行业务逻辑,然后返回。
- 过滤器可能会在发送请求之前pre或者之后post执行业务逻辑。
- pre:参数校验、权限校验、流量监控、日志输出、协议转换等。
- post:相应内容和响应头的修改,日志输出、流量监控等。
复制代码 5、案例
5.1、生产者前增加9527网关
新建module : cloud-gateway-9527
- <parent>
- <artifactId>cloud_2020</artifactId>
- <groupId>com.lee.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cloud-gateway-9527</artifactId>
复制代码 POM:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>cloud_2020</artifactId>
- <groupId>com.lee.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cloud-gateway-9527</artifactId>
- <dependencies>
- <!--新增gateway-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-gateway</artifactId>
- </dependency>
- <dependency>
- <groupId>com.lee.springcloud</groupId>
- <artifactId>cloud-api-commons</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-hystrix</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-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- </project>
复制代码 application.yml
- server:
- port: 9527
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- routes:
- - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
- uri: http://localhost:8001 #匹配后提供服务的路由地址
- predicates:
- - Path=/payment/get/** #断言,路径相匹配的进行路由
- - id: payment_routh2
- uri: http://localhost:8001
- predicates:
- - Path=/payment/lb/** #断言,路径相匹配的进行路由
- eureka:
- instance:
- hostname: cloud-gateway-service
- client:
- service-url:
- register-with-eureka: true
- fetch-registry: true
- defaultZone: http://eureka7001.com:7001/eureka
复制代码 主启动类:
- @SpringBootApplication
- @EnableEurekaClient
- public class GateWayMain9527 {
- public static void main(String[] args) {
- SpringApplication.run(GateWayMain9527.class,args);
- }
-
- }
复制代码 测试:
- 1、启动eureka7001、provider-8001、gateway-9527
- 2、访问:http://localhost:8001/payment/get/1
- 3、访问:http://localhost:9527/payment/get/1
- 结果都是:
- {"code":200,"message":"查询数据成功 serverPort:8001Payment(id=1, serial=001)","data":null}
- 实现了在8001服务前增加了一个9527。
复制代码 5.2、优化
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- routes:
- - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
- uri: http://localhost:8001 #匹配后提供服务的路由地址
- predicates:
- - Path=/payment/get/** #断言,路径相匹配的进行路由
- - id: payment_routh2
- uri: http://localhost:8001
- predicates:
- - Path=/payment/lb/** #断言,路径相匹配的进行路由
复制代码 现在我们的配置是http://localhost:8001基于微服务详细地点的。但是payment-provider的微服务在实际生产环境下大概会有多个服务。所以我们要基于provider在注册中心中的微服务名称来进行动态路由。
- 默认情况下:gateway会根据注册中心的服务列表,以注册中心上的微服务名称创建动态路由进行转发,从而实现动态路由的功能。
复制代码 修改cloud-gateway-9527 application.yml
- server:
- port: 9527
- spring:
- application:
- name: cloud-gateway
- cloud:
- gateway:
- routes:
- - id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
- ##uri: http://localhost:8001 #匹配后提供服务的路由地址
- uri: lb://cloud-payment-service #lb表示启用gateway的负载均衡功能 在eureka中根据微服务名称找到URI
- predicates:
- - Path=/payment/get/** #断言,路径相匹配的进行路由
- - id: payment_routh2
- ##uri: http://localhost:8001
- uri: lb://cloud-payment-service #lb表示启用gateway的负载均衡功能 在eureka中根据微服务名称找到URI
- predicates:
- - Path=/payment/lb/** #断言,路径相匹配的进行路由
- eureka:
- instance:
- hostname: cloud-gateway-service
- client:
- service-url:
- register-with-eureka: true
- fetch-registry: true
- defaultZone: http://eureka7001.com:7001/eureka
复制代码 测试:
- 1、启动eureka-7001、provider-8001、provider-8002、gateway-9527
- 2、访问:http://localhost:9527/payment/get/1
- 结果返回:
- {"code":200,"message":"查询数据成功 serverPort:8001Payment(id=1, serial=001)","data":null}
- 或者
- {"code":200,"message":"查询数据成功 serverPort:8002Payment(id=1, serial=001)","data":null}
- 8001和8002端口微服务轮询使用,证明我们访问9527通过微服务名称可以调用对应的微服务
复制代码 5.3、Predicate使用
我们在启动cloud-gateway-9527的时候,后台加载了如下:
- Springcloud gateway内置了许多route predicate工厂,这些prediacate都与http请求的不同属性相匹配。多个
- route predicate可以进行组合使用。
- springcloud gateway创建route对象,RoutePredicateFactory创建predicate对象,predicate对象赋值给route。
复制代码 常见的route predicate:
- 1、After Route Predicate
- 例:- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
- 2、Before Route Predicate
- 例:- After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
- 3、Between Route Predicate
- 例:- Between=2020-03-08T10:59:34.102+08:00[Asia/Shanghai] , 2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
- 4、Cookie Route Predicate
- 例:- Cookie=username,lee #并且Cookie是username=lee才能访问
- 5、Header Route Predicate
- 例:- Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
- 6、Host Route Predicate
- 例:- Host=**.ngc7293.com
- 7、Method Route Predicate
- 例:- Method=GET
- 8、Path Route Predicate
- 例:- Path=/payment/get/** #断言,路径相匹配的进行路由
- 9、Query Route Predicate
- 例:- Query=username, \d+ #要有参数名称并且是正整数才能路由
- 总结:
- - id: payment_routh2
- #uri: http://localhost:8001 #匹配后提供服务的路由地址
- uri: lb://cloud-payment-service
- predicates:
- - Path=/payment/lb/** #断言,路径相匹配的进行路由
- - After=2020-03-08T10:59:34.102+08:00[Asia/Shanghai]
- - Cookie=username,lee #并且Cookie是username=lee才能访问
- - Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
- - Host=**.ngc7293.com
- - Method=GET
- - Query=username, \d+ #要有参数名称并且是正整数才能路由
复制代码 说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理
5.4、Filter使用
网关经常需要对路由请求进行过滤,进行一些利用,如鉴权之后构造头部之类的,过滤的种类很多,如增加请求头、增加请求 参数 、增加相应头和断路器等等功能,这就用到了Spring Cloud Gateway 的 Filter。
当我们有很多个服务时,比如下图中的user-service、goods-service、sales-service等服务,客户端请求各个服务的Api时,每个服务都需要做相同的事变,比如鉴权、限流、日记输出等。
对于如许重复的工作,可以在微服务的上一层加一个全局的权限控制、限流、日记输出的Api Gateway服务,然后再将请求转发到详细的业务服务层。这个Api Gateway服务就是起到一个服务边界的作用,外接的请求访问系统,必须先通过网关层。
Spring Cloud Gateway 的 Filter 的生命周期不像 Zuul 的那么丰富,它只有两个:“pre” 和 “post”。
- PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
- POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
复制代码
Spring Cloud Gateway 的 Filter 从作用范围可分为另外两种GatewayFilter 与 GlobalFilter。
- GatewayFilter:应用到单个路由或者一个分组的路由上。
- GlobalFilter:应用到所有的路由上。
复制代码 5.4.1、GatewayFilter
使用演示:
过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Foo,值为Bar。
所有的/foo/**开始的路径都会命中配置的router。 请求http://www.abc.com/foo/get,会转到http://www.abc.com.org/get]
- spring:
- cloud:
- gateway:
- routes:
- - id: add_request_header_route
- uri: http://httpbin.org:80/get
- filters:
- - AddRequestHeader=X-Request-Foo, Bar
- - RewritePath=/foo/(?<segment>.*), /$\{segment}
- predicates:
- - Method=GET
复制代码 自定义Gateway Filter:
- @Component
- @Slf4j
- public class MyLogGatewayFilter implements GatewayFilter, Ordered {
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- log.info("-----welcome to MyLogGatewatFilter------"+new Date());
- String username = exchange.getRequest().getQueryParams().getFirst("username");
- if(StringUtils.isEmpty(username)){
- log.info("username is empty!!!");
- exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
- return exchange.getResponse().setComplete();
- }
- return chain.filter(exchange);
- }
- @Override
- public int getOrder() {
- return 0;
- }
- }
复制代码 config:
- @Configuration
- public class GatewayConfig {
- @Bean
- public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder){
- RouteLocatorBuilder.Builder myLogGatewayFilterBuilder = routeLocatorBuilder.routes().route("myLogGatewayFilter",
- r -> r.path("/payment/get/**")
- .uri("lb://cloud-payment-service")
- .filter(new MyLogGatewayFilter()));
- return myLogGatewayFilterBuilder.build();
- }
- }
复制代码 测试:
- 1、启动eureka-7001、payment-provider-8001、payment-provider-8002、gateway-9527
- 2、访问:http://localhost:9527/payment/get/1
- 结果:失败
- 3、访问:http://localhost:9527/payment/get/1?username=lee
- 结果:
- {"code":200,"message":"查询数据成功 serverPort:8001Payment(id=1, serial=001)","data":null}
复制代码 5.4.2、GlobalFilter
自定义globalFilter
- @Component
- @Slf4j
- public class MyGlobalGatewayFilter implements GlobalFilter, Ordered {
- @Override
- public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
- log.info("-----welcome to MyGlobalGatewatFilter------"+new Date());
- String password = exchange.getRequest().getQueryParams().getFirst("password");
- if(StringUtils.isEmpty(password)){
- log.info("password is empty!!!");
- exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
- return exchange.getResponse().setComplete();
- }
- return chain.filter(exchange);
- }
- @Override
- public int getOrder() {
- return 0;
- }
- }
复制代码 测试:
- 1、启动eureka-7001、payment-provider-8001、payment-provider-8002、gateway-9527
- 2、访问:http://localhost:9527/payment/get/1
- 结果:失败
- 3、访问:http://localhost:9527/payment/get/1?username=lee
- 结果:失败
- 4、访问:http://localhost:9527/payment/get/1?username=lee&password=admin123
- 结果:
- {"code":200,"message":"查询数据成功 serverPort:8001Payment(id=1, serial=001)","data":null}
复制代码 二、分布式配置中心Config
1、Config概述
- springcloud config提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置。
- springcloud config是一套集中式的、动态配置管理服务
复制代码 springcloud config 分为 服务端 和 客户端两部分。
- 服务端也成为分布式配置中心,他是一个独立的微服务应用,用来连接配置服务器,并为客户端提供获取配置信息,加密解密信息等访问接口。
- 客户端则通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。
- 配置服务器默认采用Git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过Git客户端工具来访问和管理配置内容。
复制代码 能干什么:
- 1、集中管理配置文件
- 2、不同环境不同配置,动态化的配置更新,分环境部署dev test prod beta release
- 3、运行期间动态调整配置
- 4、当配置发生变动时,服务不需要重启即可感知
- 5、将配置信息以rest接口形式暴露
复制代码 2、案例
2.1、服务端config-server
2.1.1、新建仓库
- ①、在码云上新建springcloud-config2020仓库
- ②、获得SSH协议的Git地址
- ③、本地硬盘目录上新建Git仓库并clone
- git clone xxxxxxxxxxxxxxxxxxxxxxxxxxx.git
- ④、新建一个application.yml(文件内容保存的格式一定要UTF-8)
- ⑤、将上yml文件推送到gitee上
- git status #查看状态
- git add .
- git commit -m "init file"
- git push origin master
复制代码 application.yml【将作为config-client端的配置文件】
- spring:
- application:
- name: cloud-payment-service #自己的服务名称
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- driver-class-name: org.gjt.mm.mysql.Driver
- url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
- username: root
- password: admin123
- eureka:
- client:
- register-with-eureka: true #向eureka server注册自己
- fetch-registry: true #需要去注册中心获取其他服务的地址
- service-url:
- #defaultZone: http://localhost:7001/eureka #单机 指向Eureka服务注册中心
- defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002:7002.com/eureka #集群 执行Eureka服务注册中心
- instance:
- instance-id: cloud-provider-payment-service-8007
- prefer-ip-address: true #是否显示服务IP地址
- mybatis:
- mapper-locations: classpath:mapper/*.xml
- type-aliases-package: com.lee.springcloud.entities
- ##configuration:
- ##log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #控制台打印SQL
复制代码 2.1.2、新建配置中心
新建module模块 cloud-config-3344配置中心模块
- <parent>
- <artifactId>cloud_2020</artifactId>
- <groupId>com.lee.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cloud-config-3344</artifactId>
复制代码 POM
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>cloud_2020</artifactId>
- <groupId>com.lee.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cloud-config-3344</artifactId>
- <dependencies>
- <!--config server-->
- <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>
-
-
-
- <dependency>
- <groupId>com.lee.springcloud</groupId>
- <artifactId>cloud-api-commons</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- </project>
复制代码 application.yml
- server:
- port: 3344
- spring:
- application:
- name: cloud-config
- cloud:
- config:
- server:
- git:
- uri: https://gitee.com/night_wish/sprincloud-config2020.git #Gitee上对应仓库的名称
- username: sssssssss@qq.com #Gitee对应的账号和密码
- password: ssssssssssssss
- search-paths:
- - sprincloud-config2020 #对应的仓库名称
- label: master #对应的分支
- eureka:
- client:
- service-url:
- defaultZone: http://eureka7001.com:7001/eureka
复制代码 主启动类:
- @SpringBootApplication
- @EnableConfigServer
- public class ConfigMain3344 {
- public static void main(String[] args) {
- SpringApplication.run(ConfigMain3344.class,args);
- }
- }
复制代码 2.1.3、其他配置
- 修改HOST
- 127.0.0.1 config3344.com
- ①①、启动config 测试是否可以从gitee上获取配置内容
- http://config3344.com:3344/application-dev.yml
- http://config3344.com:3344/application-test.yml
- http://config3344.com:3344/application-xxxxx.yml
- 或
- http://config3344.com:3344/application/dev/master
- http://config3344.com:3344/application/test/master
- http://config3344.com:3344/application/xxxxx/master
复制代码 2.2、客户端config-client
客户端即微服务,仿照cloud-provider-payment-8001创建cloud-provider-payment-8007
POM
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>cloud_2020</artifactId>
- <groupId>com.lee.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <packaging>jar</packaging>
- <artifactId>cloud-provider-payment-8007</artifactId>
- <dependencies>
-
- <!-- SpringCloud Config客户端 -->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-config</artifactId>
- </dependency>
- <!--Eureka client-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <!--springboot-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>1.1.10</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <scope>runtime</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.projectlombok</groupId>
- <artifactId>lombok</artifactId>
- <optional>true</optional>
- </dependency>
- <!--cloud-api-commons公共包-->
- <dependency>
- <groupId>com.lee.springcloud</groupId>
- <artifactId>cloud-api-commons</artifactId>
- <version>${project.version}</version>
- </dependency>
- </dependencies>
- </project>
复制代码 application.yml
bootstrap.yml
- spring:
- cloud:
- config:
- name: application #需要从gitee上读取的资源名称,注意没有yml后缀名
- profile: dev #本次访问的配置项
- label: master
- uri: http://config3344.com:3344 #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取Gitee的服务地址
复制代码 创建ConfigClientRestController类
- @RestController
- public class ConfigClientRestController {
- @Value("${spring.application.name}")
- private String applicationName;
- @Value("${eureka.client.service-url.defaultZone}")
- private String eurekaServers;
- @Value("${server.port}")
- private String port;
- @Value("${config.info}")
- private String info;
- @RequestMapping("/config")
- public String getConfig()
- {
- String str = "applicationName: "+applicationName+"\t eurekaServers:"+eurekaServers+"\t port: "+port;
- System.out.println("******str: "+ str);
- return "applicationName: "+applicationName+"\t eurekaServers:"+eurekaServers+"\t port: "+port;
- }
- @RequestMapping("/info")
- public String getName(){
- return "config.info : "+info;
- }
- }
复制代码 主启动类:
- //服务发现
- @EnableDiscoveryClient
- //表示自己是Eureka的客户端
- @EnableEurekaClient
- @SpringBootApplication
- @MapperScan("com.lee.springcloud.dao")
- public class PaymentMain8007 {
- public static void main(String[] args) {
- SpringApplication.run(PaymentMain8007.class,args);
- }
- }
复制代码 其余的controller、service、dao、mapper仿照cloud-payment-provider-8001创建
测试:
- 1、启动eureka-7001、config-3344、cloud-provider-payment-8007
- 2、访问 http://localhost:8007/info
- 结果:
- config.info : hello-world
- 证明可以通过config-3344访问 码云上的application.yml配置信息可以读取其内容
- 3、访问 http://localhost:8007/payment/get/1
- 结果:
- {"code":200,"message":"查询数据成功 serverPort:8007Payment(id=1, serial=001)","data":null}
- 证明可以通过config-3344访问 码云上的application.yml配置信息可以访问数据库
复制代码 2.3、客户端只动态刷新的问题
在码云 sprincloud-config2020 上修改application.yml
- config:
- info: hello-world2 #原来是hello-world
复制代码 访问: http://localhost:3344/application-dev.yml
- 结果:
- config:
- info: hello-world2
- 。。。。其余省略
复制代码 访问: http://localhost:8007/info
- 结果:
- config.info : hello-world
复制代码 重启cloud-provider-payment-8007,访问http://localhost:8007/info
- 结果:
- config.info : hello-world
- 2
复制代码 解决方案:
cloud-provider-payment-8007 引入actuator监控
pom
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-actuator</artifactId>
- </dependency>
复制代码 application.yml
- management:
- endpoints:
- web:
- exposure:
- include: "*"
复制代码 controller新增
运维人员手动发送POST请求刷新8007
- curl -X POST "http://localhost:8007/actuator/refresh"
复制代码 测试:
- 1、修改码云config: info: hello-world32、访问http://localhost:3344/application-dev.yml结果:
- config:
- info: hello-world2
- 。。。。其余省略
- 3、访问http://localhost:8007/info结果:
- config.info : hello-world
- 3
复制代码 三、消息总线Bus
上述config客户端,假如有多个cloud-provider-payment-800XXX,运维人员每次修改配置文件,都需要手动POST请求,手动刷新非常麻烦。因此能否广播,一次关照处处生效,大范围的刷新。这就引出了消息总线BUS。
1、概述
- springcloud bus是用来将分布式系统的节点 与 轻量级消息系统 链接起来的框架。
- 它整合了java事件处理机制和消息中间件的功能
- SpringCloud Bus 目前仅支持RabbitMq和Kafka
- springcloud bus能管理和传播分布式系统间的消息,就像一个分布式执行器,可用于广播状态更改、时间推送等。
- 也可以当做微服务间的通信通道。
复制代码
- 什么是总线
- 在微服务架构的系统中,通常会使用轻量级的消息代理来构建一个公用的消息主题,并让系统中的所有微服务实例都连接上来。由于该主题中产生的消息会被所有实例监听和消费,所以称为消息总线。在总线上的各个实例,都可以方便地广播一些需要让其他链接在该主题行的实例都知道的消息。
-
- 基本原来理:
- ConfigClient实例都监听MQ中的同一个topic(默认是SpringcloudBus)。当一个服务刷新数据的时候,它会把这个信息放入到topic中,这样其它监听同一个topic的服务就能得到通知,然后去更新自身的配置。
复制代码 2、安装RabbotMq
- ①、安装Erlang环境
- http://erlang.org/download/otp_win64_21.3.exe
- ②、安装Rabbit
- https://dl.bintray.com/rabbitmq/all/rabbitmq-server/3.7.14/rabbitmq-server-3.7.14.exe
- ③、启动管理添加可视化插件
- cd F:\JavaTools\RabbitMq\rabbitmq_server-3.7.14\sbin
- 执行 rabbitmq-plugins enable rabbitmq_management
- ④、启动rabbitmq,并访问http://localhost:15672/
- 账号:guest 密码:guest
复制代码
3、创建另一个config-client
再以cloud-provider-payment-8007创建一个config-client
cloud-provider-payment-8008
- <parent>
- <artifactId>cloud_2020</artifactId>
- <groupId>com.lee.springcloud</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>cloud-provider-payment-8008</artifactId>
复制代码 application.yml
主启动类
- //服务发现
- @EnableDiscoveryClient
- //表示自己是Eureka的客户端
- @EnableEurekaClient
- @SpringBootApplication
- @MapperScan("com.lee.springcloud.dao")
- public class PaymentMain8008 {
- public static void main(String[] args) {
- SpringApplication.run(PaymentMain8008.class,args);
- }
- }
复制代码 4、设计思想
4.1、使用消息总线触发一个客户端/bus/refresh,而刷新所有客户端的配置
4.2、使用消息总线触发一个服务端ConfigServer的/bus/refresh端点,而刷新所有客户端的配置(更加推荐)
5、动态刷新全局广播案例
5.1、config-server添加消息总线支持
cloud-config-3344
POM新增
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-bus-amqp</artifactId>
- </dependency>
复制代码 yml新增
- server:
- port: 3344
- spring:
- application:
- name: cloud-config
- cloud:
- config:
- server:
- git:
- uri: https://gitee.com/night_wish/sprincloud-config2020.git #Gitee上对应仓库的名称
- username: ooooooooo
- password: xxxxxxxxx
- search-paths:
- - sprincloud-config2020
- label: master
- eureka:
- client:
- service-url:
- defaultZone: http://eureka7001.com:7001/eureka
- #新增bus
- rabbitmq:
- host: localhost
- port: 5672
- username: guest
- password: guest
- #新增bus
- management:
- endpoints:
- web:
- exposure:
- include: 'bus-refresh'
复制代码 controller新增
- @RefreshScope
- //新增@RestControllerpublic class ConfigClientRestController { //。。。。省略}
复制代码 5.2、config-client添加消息总线支持
cloud-provider-payment-8007 和 cloud-provider-payment-8008
POM新增
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-bus-amqp</artifactId>
- </dependency>
复制代码 bootstrap.yml
- spring: cloud: config: name: application #需要从gitee上读取的资源名称,留意没有yml后缀名 profile: dev #本次访问的配置项 label: master uri: http://config3344.com:3344 #本微服务启动后先去找3344号服务,通过SpringCloudConfig获取Gitee的服务地点#新增rabbitmq: host: localhost port: 5672 username: guest password: guest#新增management:
- endpoints:
- web:
- exposure:
- include: "*"
复制代码 5.3、测试
- 1、启动eureka-7001 config-3344 cloud-provider-payment-8007 cloud-provider-payment-8008
- 2、访问:
- http://localhost:3344/application-dev.yml
- http://localhost:8007/info
- http://localhost:8008/info
- 结果:
- config:
- info: hello-world3
- 和
- config.info : hello-world3
- 和
- config.info : hello-world3
- 3、修改码云上springcloud-config2020中application.yml数值hello-world3为hello-world4
- 4、再次访问以上
- 结果:
- config:
- info: hello-world4
- 和
- config.info : hello-world3
- 和
- config.info : hello-world3
- 5、运维人员发送刷新到config-server
- curl -X POST "http://localhost:3344/actuator/bus-refresh"
- 6、再次访问以上
- 结果:
- config:
- info: hello-world4
- 和
- config.info : hello-world4
- 和
- config.info : hello-world4
- 总结:
- 我们利用消息总线触发一个服务端ConfigServer(config-3344)的/bus/refresh端点,而刷新所有客户端的配置
复制代码 6、动态刷新定点关照案例
偶尔候我们需要数据更新后只刷新某一个或几个config-client,而不是全部的config-client,因此动态刷新定点关照就很紧张了。
公式:
- http://localhost:配置中心的端口号/actuator/bus-refresh/{destination}
复制代码 案例测试:
- 1、启动eureka-7001 config-3344 cloud-provider-payment-8007 cloud-provider-payment-8008
- 2、访问:
- http://localhost:3344/application-dev.yml
- http://localhost:8007/info
- http://localhost:8008/info
- 结果:
- config:
- info: hello-world4
- 和
- config.info : hello-world4
- 和
- config.info : hello-world4
- 3、修改码云上springcloud-config2020中application.yml数值hello-world4为hello-world5
- 4、再次访问以上
- 结果:
- config:
- info: hello-world5
- 和
- config.info : hello-world4
- 和
- config.info : hello-world4
- 5、运维人员发送刷新到config-server
- curl -X POST "http://localhost:3344/actuator/bus-refresh/cloud-payment-service:8007"
- 6、再次访问以上
- 结果:
- config:
- info: hello-world5
- 和
- config.info : hello-world5
- 和
- config.info : hello-world4
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |