# Spring Cloud **Repository Path**: xxkfz/spring-cloud ## Basic Information - **Project Name**: Spring Cloud - **Description**: 记录学习SpringCloudAlibaba的笔记和代码;主要来自b站尚硅谷SpringCloud框架开发教程以及SpringCloudAlibaba微服务分布式架构等视频。同时会记录平时一些学习和项目中遇到的问题,学习记录将会同步更新到该仓库地址。 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-22 - **Last Updated**: 2023-01-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringCloud, 微服务, SpringCloudAlibaba, Java ## README ![微信公众号](./doc/SpringCloud学习/xxkfz_guanzhu.png) ​ `学习时间 2021-06` 学习路线:理论——>实操——>小总结 # **SpringCloud学习记录笔记** 视频地址:https://www.bilibili.com/video/BV18E411x7eT?p=37&spm_id_from=pageDriver 笔记地址: (一)、https://blog.csdn.net/u011863024/article/details/114298270 (二)、https://blog.csdn.net/u011863024/article/details/114298282 (三)、https://blog.csdn.net/u011863024/article/details/114298288 ### **一、服务注册中心** #### **1.1、Eureka(停更)** 项目思维导图: ![](./doc/SpringCloud学习/Eureka服务注册与发现.png) ![](./doc/SpringCloud学习/Eureka-server.jpg) #### **1.2、Zookeeper** #### **1.3、Consul** ##### 1.3.1、Consul是什么? 官网:https://www.consul.io/docs/intro ##### 1.3.2、Consul下载安装使用 关于Consul的安装,详见Linux服务器软件安装及项目部署.docs文档! ![image-20210808152926884](./doc/SpringCloud学习/Snipaste_2021-08-08_15-32-36.jpg) ##### 1.3.3、服务提供者注册进Consul (1)在springcloud项目工程下面,创建模块——cloud-providerconsul-payment8006。 ![](./doc/SpringCloud学习/Snipaste_2021-08-08_15-35-15.jpg) (2)在pom.xml添加所需依赖。 ```xml com.xxkfz cloud-api-commons ${project.version} org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test cn.hutool hutool-all RELEASE test mysql mysql-connector-java org.mybatis.spring.boot mybatis-spring-boot-starter ``` (3)创建配置文件。(application.yml) ```xml ###consul服务端口号 server: port: 8006 spring: application: name: consul-provider-payment # 对外暴露的服务名称: consul-provider-payment ####consul注册中心地址 cloud: consul: host: localhost port: 8500 discovery: #hostname: 127.0.0.1 service-name: ${spring.application.name} datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://118.31.187.5:3306/springcloud?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8 username: root password: root # 整合mybatis mybatis: type-aliases-package: com.xxkfz.springcloud.entity mapper-locations: classpath:mybatis/mapper/*.xml # 打印sql logging: level: com: xxkfz: springcloud: dao: debug ``` (4)创建主启动类PaymentMain8006。 ```java package com.xxkfz.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @program: springcloud2021 * @description: * @author: xxkfz * @create: 2021-08-08 12:05 **/ @SpringBootApplication @EnableDiscoveryClient public class PaymentMain8006 { public static void main(String[] args) { SpringApplication.run(PaymentMain8006.class,args); } } ``` (5)编写简单的业务处理逻辑。 ```java package com.xxkfz.springcloud.controller; import com.xxkfz.springcloud.entity.Payment; import com.xxkfz.springcloud.service.PaymentService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.UUID; /** * @program: springcloud2021 * @description: * @author: xxkfz * @create: 2021-08-08 12:07 **/ @RestController @RequestMapping("/consul-provider-payment") @Slf4j public class PaymentController { @Autowired private PaymentService paymentService; @Value("${server.port}") private String serverPort; @RequestMapping(value = "/payment/consul") public String paymentConsul() { return "springcloud with consul: " + serverPort + "\t " + UUID.randomUUID().toString(); } @GetMapping("/allPaymentList") public List getAllPayment(){ return paymentService.getAllPayment(); } } ``` (6)测试。 启动PaymentMain8006,在浏览器地址栏中输入:http://localhost:8006/consul-provider-payment/allPaymentList ![](./doc/SpringCloud学习/Snipaste_2021-08-08_15-41-17.jpg) 访问:http://127.0.0.1:8500/,将会显示服务提供者cloud-providerconsul-payment8006注册进Consul。 ![](./doc/SpringCloud学习/Snipaste_2021-08-08_15-44-37.jpg) 到这里,服务提供者就完成了。 4、服务消费者注册进Consul (1)创建服务消费者Module——cloud-consumerconsul-order80。 ![](./doc/SpringCloud学习/Snipaste_2021-08-08_15-55-09.png) (2)在pom.xml文件中添加所需依赖。 ```xml com.xxkfz cloud-api-commons ${project.version} org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test ``` (3)添加配置文件application.yml。 ```yml ###consul服务端口号 server: port: 80 spring: application: name: cloud-consumer-order ####consul注册中心地址 cloud: consul: host: localhost port: 8500 discovery: #hostname: 127.0.0.1 service-name: ${spring.application.name} ``` (4)创建主启动类OrderConsulMain80.java ```java package com.xxkfz.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @program: springcloud2021 * @description: * @author: xxkfz * @create: 2021-08-08 12:58 **/ @SpringBootApplication @EnableDiscoveryClient public class OrderConsulMain80 { public static void main(String[] args) { SpringApplication.run(OrderConsulMain80.class,args); } } ``` (5)配置Bean。 ```java package com.xxkfz.springcloud.config; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * @program: springcloud2021 * @description: * @author: xxkfz * @create: 2021-08-08 12:58 **/ @Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } } ``` (6)编写简单Controller,调用服务提供者。 ```java package com.xxkfz.springcloud.controller; import com.xxkfz.springcloud.entity.Payment; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import java.util.List; /** * @program: springcloud2021 * @description: * @author: xxkfz * @create: 2021-08-08 12:59 **/ @RestController @Slf4j @RequestMapping("/cloud-consumer-order") public class OrderConsulController { public static final String INVOKE_URL = "http://consul-provider-payment"; @Resource private RestTemplate restTemplate; @GetMapping(value = "/allPaymentList") public List paymentInfo() { log.info("服务消费者开始调用服务生产者.........."); List paymentList = restTemplate.getForObject(INVOKE_URL+"/consul-provider-payment/allPaymentList", List.class); return paymentList; } } ``` (7)测试。 同时启动服务:consul-provider-payment、cloud-consumer-order!!! 在浏览器的地址栏中输入:http://localhost/cloud-consumer-order/allPaymentList ![](./doc/SpringCloud学习/Snipaste_2021-08-08_16-05-12.jpg) 现在访问:http://127.0.0.1:8500/,看到服务提供者:consul-provider-payment;服务消费者:cloud-consumer-order成功注册注册进Consul。 ![](./doc/SpringCloud学习/Snipaste_2021-08-08_16-07-38.jpg) #### Nacos ### **二、服务调用** #### **2.1、Ribbon负载均衡服务调用** ##### **2.1.1、基本概念** Spring Cloud Ribbon是基于Netflix Ribbon实现的一套**客户端负载均衡的工具**。 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供**客户端的软件负载均衡算法和服务调用**。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。 架构图: ![](./doc/SpringCloud学习/Ribbon架构说明.png) 如何使用spring-cloud-starter-ribbon? 在pom.xml文件中引入: ```yml org.springframework.cloud spring-cloud-starter-netflix-ribbon ``` 注意:spring-cloud-starter-netflix-eureka-client自带了spring-cloud-starter-ribbon引用,因此我们不需要再需引入。 ![](./doc/SpringCloud学习/Snipaste_2021-08-21_13-41-07.jpg) ##### **2.1.2、RestTemplate的使用** 1、GET请求方法 getForObject():返回对象为响应体中数据转化成的对象,基本上可以理解为Json。 getForEntity():返回对象为ResponseEntity对象,包含了响应中的一些重要信息,比如响应头、响应状态码、响应体等。 演示示例(getForObject方法与getForEntity方法): ```java @GetMapping("/consumer/payment/get/{id}") public CommonResult getPayment(@PathVariable("id") Long id) { List serviceInstances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); return restTemplate.getForObject(ServerUrlConstants.PAYMENT_SERVICE_NAME + ServerUrlConstants.GET_URL + id, CommonResult.class); } @GetMapping("/consumer/payment/getForEntity/{id}") public CommonResult getPayment2(@PathVariable("id") Long id) { ResponseEntity forEntity = restTemplate.getForEntity(ServerUrlConstants.PAYMENT_SERVICE_NAME + ServerUrlConstants.GET_URL + id, CommonResult.class); if (forEntity.getStatusCode().is2xxSuccessful()) { return forEntity.getBody(); } else { return new CommonResult<>(444, "操作失败!"); } } ``` 2、POST请求方法 postForObject方法 postForEntity方法 ##### **2.1.3、Ribbon核心组件IRule** Ribbon默认自带的7种负载规则:默认采用的是轮询。 - RoundRobinRule 轮询 - RandomRule 随机 - RetryRule 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试 - WeightedResponseTimeRule 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择 - BestAvailableRule 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 - AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例 - ZoneAvoidanceRule 默认规则,复合判断server所在区域的性能和server的可用性选择服务器 Ribbon的负载规则如何替换为其他的? 基本替换步骤如下: ![](./doc/SpringCloud学习/Ribbon的负载规则替换.jpg) 主要代码: 1、MySelfRule.java ```java package com.xxkfz.myrule; import com.netflix.loadbalancer.IRule; import com.netflix.loadbalancer.RandomRule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @program: springcloud2021 * @description: Ribbon负载规则替换 * @author: xxkfz * @create: 2021-08-21 16:39 **/ @Configuration public class MySelfRule { @Bean public IRule myRule() { return new RandomRule(); } } ``` 2、主启动类: ```java @SpringBootApplication @EnableEurekaClient //@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class) public class OrderMain80 { public static void main( String[] args ){ SpringApplication.run(OrderMain80.class, args); } } ``` 测试结果: 在浏览器地址栏种输入 http://localhost/consumer/payment/get/1 返回结果中的serverPort在8001与8002两种间反复横跳。 ![](./doc/SpringCloud学习/Snipaste_2021-08-21_17-08-55.jpg) ##### 2.1.4、Ribbon默认负载轮询算法原理 默认负载轮训算法: rest接口第几次请求数 % 服务器集群总数量 = 实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始。 ```java List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); ``` 如: List [0] instances = 127.0.0.1:8002 List [1] instances = 127.0.0.1:8001 8001+ 8002组合成为集群,它们共计2台机器,集群总数为2,按照轮询算法原理: 当总请求数为1时:1%2=1对应下标位置为1,则获得服务地址为127.0.0.1:8001 当总请求数位2时:2%2=О对应下标位置为0,则获得服务地址为127.0.0.1:8002 当总请求数位3时:3%2=1对应下标位置为1,则获得服务地址为127.0.0.1:8001 当总请求数位4时:4%2=О对应下标位置为0,则获得服务地址为127.0.0.1:8002 如此类推… ##### **2.1.5、Ribbon之手写轮询算法** ![](./doc/SpringCloud学习/Ribbon之手写轮询算法.jpg) ### **三、服务调用2** #### **3.1、OpenFeign服务接口调用** ![](./doc/SpringCloud学习/Snipaste_2021-08-21_22-16-32.jpg) ##### **3.1.1、OpenFeign的简单使用** 1、创建Module——cloud-consumer-feign-order80 ![](./doc/SpringCloud学习/Snipaste_2021-08-21_21-45-48.jpg) 2、添加所需依赖。 ```yml org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-netflix-eureka-client com.xxkfz cloud-api-commons ${project.version} org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test cn.hutool hutool-all ``` 观察发现? 在以上添加openfeign的依赖后,自带了Ribbon负载均衡功能。 ![](./doc/SpringCloud学习/Snipaste_2021-08-21_21-49-15.jpg) 3、创建配置文件application.yml。 ```xml # 服务端口配置 server: port: 80 # Eureka相关配置 eureka: client: #表示是否将自己注册进Eurekaserver默认为true。 register-with-eureka: true #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: defaultZone: http://110.40.174.58:7001/eureka,http://110.40.174.58:7002/eureka # defaultZone: http://localhost:7001/eureka instance: instance-id: consumer-feign-order80 ``` 4、编写主启动类。 ```java @SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class, args); } } ``` 注:在启动类上面加上@EnableFeignClients注解。 5、编写业务类。 在包com.xxkfz.springcloud.service下面,创建调用服务提供者的业务类PaymentFeignService,并在类上加上@FeignClient(value = "CLOUD-PAYMENT-SERVICE")注解。 ```java @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id); @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(); } ``` 6、编写Controller。 ```java @RestController @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id) { return paymentFeignService.getPaymentById(id); } @GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout() { // OpenFeign客户端一般默认等待1秒钟 return paymentFeignService.paymentFeignTimeout(); } } ``` 7、测试。 (1)启动Eureka-server7001、Eureka-server7002,2个Eureka集群。 (2)启动服务提供者两个微服务cloud-provider-payment8001、cloud-provider-payment8002。 (3)启动服务消费者cloud-consumer-feign-order80。 启动完成,如下图所示: ![](./doc/SpringCloud学习/Snipaste_2021-08-22_10-33-00.jpg) 访问:http://110.40.174.58:7001/ 可以看到,服务已经注册到Eureka上面。 ![](./doc/SpringCloud学习/Snipaste_2021-08-22_10-35-32.jpg) 访问:http://127.0.0.1/consumer/payment/get/1 ![](./doc/SpringCloud学习/Snipaste_2021-08-22_10-36-52.jpg) ##### 3.1.2、OpenFeign超时控制 超时设置,故意设置超时演示出错情况: 1、服务提供方cloud-provider-payment8001、cloud-provider-payment8002故意写暂停程序: ```java @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout() { // 业务逻辑处理正确,但是需要耗费3秒钟 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return serverPort; } ``` 2、服务消费方PaymentFeignService添加超时方法: ```java @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(); ``` 3、服务消费方OrderFeignController添加超时方法: ```java @GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout() { // OpenFeign客户端一般默认等待1秒钟 return paymentFeignService.paymentFeignTimeout(); } ``` 4、测试:访问地址:http://localhost/consumer/payment/feign/timeout ![](./doc/SpringCloud学习/Snipaste_2021-08-22_10-46-03.jpg) 如何解决该问题呢?只需要在配置文件`application.yml`中开启OpenFeign客户端超时控制即可!!! ```yml #设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒) ribbon: #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ReadTimeout: 5000 #指的是建立连接后从服务器读取到可用资源所用的时间 ConnectTimeout: 5000 ``` ##### 3.1.3、OpenFeign的日志增强 **日志打印功能** Feign提供了日志打印功能,我们可以通过配置来调整日恙级别,从而了解Feign 中 Http请求的细节。 说白了就是对Feign接口的调用情况进行监控和输出。 **日志级别** - NONE:默认的,不显示任何日志; - BASIC:仅记录请求方法、URL、响应状态码及执行时间; - HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息; - FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。 怎样使用呢? 1、配置日志bean。在config包下面创建FeignConfig。 ```java @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } } ``` 2、配置文件开启Feign的客户端。 ```yml # 配置开启日志的Feign客户端 logging: level: # feign日志以什么级别监控哪个接口 com.xxkfz.springcloud.service.PaymentFeignService: debug ``` 3、重启cloud-consumer-feign-order80微服务,访问http://127.0.0.1/consumer/payment/get/1 查看cloud-consumer-feign-order80的后台日志输出,得到更多日志信息。 ![](./doc/SpringCloud学习/Snipaste_2021-08-22_12-44-28.jpg) ### **四、服务降级** #### **4.1、Hystrix断路器** ##### **4.1.1、Hystrix基本概念** Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。 "断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。 ##### **4.1.2、Hystrix能干什么** - 服务降级 - 服务熔断 - 接近实对的监控 - … Hystrix停止更新,进入维护阶段。 ##### **4.1.3、Hystrix的服务降级熔断限流概念** **服务降级** 服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback 那么哪些情况会发生服务降级? a、程序运行异常 b、超时 c、服务熔断触发服务降级 d、线程池/信号量打满也会导致服务降级 **服务熔断** 类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示。 **服务限流** (sentinel) 秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行。 #### 4.2sentinels ### **五、服务网关** #### **4.1、Zuul(不做介绍)** #### 4.2、gateway网关 网关在微服务中的位置: ![](./doc/SpringCloud学习/Snipaste_2021-10-22_20-38-45.jpg) Spring Cloud uolGateway的三大核心概念: - Route路由:路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由; - Predicate断言 - Filter过滤 **核心逻辑**:路由转发 + 执行过滤器链。 ![](./doc/SpringCloud学习/Snipaste_2021-08-29_15-17-09.jpg) **gateway项目搭建:** 1、新建网关模块:cloud-gateway-gateway9527 项目结构如下所示: ![](./doc/SpringCloud学习/Snipaste_2021-10-22_19-59-29.jpg) 在该模块下面主要引入gateway依赖: ```xml org.springframework.cloud spring-cloud-starter-gateway ``` 全部的依赖如下: ```xml org.springframework.cloud spring-cloud-starter-gateway org.springframework.cloud spring-cloud-starter-netflix-eureka-client com.xxkfz cloud-api-commons ${project.version} org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test ``` 2、在配置文件中,配置相关的信息后,启动网关模块,可以看到该服务注册进Eureka。 ![](./doc/SpringCloud学习/Snipaste_2021-10-22_20-04-17.jpg) 3、启动服务提供者:cloud-provider-payment8001。 4、测试。 添加网关之前,访问服务提供者的接口:http://localhost:8001/payment/get/1 ![](./doc/SpringCloud学习/Snipaste_2021-10-22_20-08-46.jpg) 在网关模块,application.yml中增加如下网关配置信息: ```xml cloud: gateway: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由 routes: - id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 # uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service #匹配后提供服务的路由地址 #uri: lb://cloud-payment-service #匹配后提供服务的路由地址 predicates: - Path=/payment/get/** # 断言,路径相匹配的进行路由 - id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名 # uri: http://localhost:8001 #匹配后提供服务的路由地址 uri: lb://cloud-payment-service #匹配后提供服务的路由地址 #uri: lb://cloud-payment-service #匹配后提供服务的路由地址 predicates: - Path=/payment/lb/** # 断言,路径相匹配的进行路由 ``` 添加了网关之后,访问:http://localhost:9527/payment/get/1 ![](./doc/SpringCloud学习/Snipaste_2021-10-22_20-47-56.jpg) ![](./doc/SpringCloud学习/Snipaste_2021-10-22_20-11-55.jpg) ##### **4.2.1、GateWay配置路由的两种方式** - 第一种方式:在配置文件application.yml中进行配置,例如上面的例子。 - 第二种方式:代码中注入RouteLocator的Bean 下面演示的是第二种方式: 1、在cloud-gateway-gateway9527添加配置类GateWayConfig.java ```java /** * @program: springcloud2021 * @description: 演示Gateway配置路由的第二种方式:硬编码方式 * @author: xxkfz * @create: 2021-08-29 17:24 **/ @Configuration public class GateWayConfig { @Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { /** * https://news.baidu.com/guonei * 访问9527/guonei 将会跳转到https://news.baidu.com/guonei 这个地址 */ RouteLocatorBuilder.Builder routes = builder.routes(); routes.route("path_route_xxkfz", r -> r.path("/guonei") .uri("https://news.baidu.com/guonei")) .build(); return routes.build(); } } ``` 2、测试。 浏览器输入http://localhost:9527/guonei,返回http://news.baidu.com/guonei相同的页面,效果如下: ![](./doc/SpringCloud学习/Snipaste_2021-10-31_11-46-48.jpg) ##### **4.2.2、GateWay常用的Predicate(断言)** ###### 4.2.2.1、演示- After的使用 ![](./doc/SpringCloud学习/Snipaste_2021-10-31_12-39-05.jpg) 说明: ```xml - After=2021-10-31T12:12:30.195+08:00[Asia/Shanghai] ``` 在这个时间后才能起效 那么这个时间怎样获取呢? com.xxkfz.springcloud.test.Test ```java /** * @program: springcloud2021 * @description: 测试类 * @author: xxkfz * @create: 2021-10-31 12:09 **/ public class Test { public static void main(String[] args) { ZonedDateTime now = ZonedDateTime.now(); System.out.println(now); } } ``` 若设置的时间为大于当前时间:访问http://127.0.0.1:9527/payment/lb ![](./doc/SpringCloud学习/Snipaste_2021-10-31_12-45-00.jpg) 若设置的时间为小于当前时间,访问http://127.0.0.1:9527/payment/lb ![](./doc/SpringCloud学习/Snipaste_2021-10-31_12-46-44.jpg) ###### **4.2.2.2演示-Cookie** ![](./doc/SpringCloud学习/Snipaste_2021-10-31_12-52-51.jpg) 说明:携带Cookie可以成功访问。 在cmd终端访问 curl http://localhost:9527/payment/lb --cookie "username=xxkfz" ![](./doc/SpringCloud学习/Snipaste_2021-10-31_12-54-01.jpg) 不带Cookie将会访问失败。 ![](./doc/SpringCloud学习/Snipaste_2021-10-31_12-55-12.jpg) ###### **4.2.2.3、演示-Header** ![](./doc/SpringCloud学习/Snipaste_2021-10-31_13-54-11.jpg) 说明: ```xml - Header=X-Request-Id, \d+ # 请求头中要带有-Request-Id属性并且值为整数的正则表达式。 ``` 演示:在cmd终端输入: ```c curl http://localhost:9527/payment/lb -H "X-Request-Id:123" ``` 可以成功访问。 ![](./doc/SpringCloud学习/Snipaste_2021-10-31_13-55-51.jpg) 访问: ```c curl http://localhost:9527/payment/lb -H "X-Request-Id:-123" ``` 将会访问失败!!! ###### **4.2.2.4、总结** 说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。 ##### **4.2.3、GateWay的Filter** 自定义全局GlobalFilter: ```java @Component @Slf4j public class MyLogGateWayFilter implements GlobalFilter, Ordered { @Override public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { log.info("***********come in MyLogGateWayFilter: " + new Date()); String uname = exchange.getRequest().getQueryParams().getFirst("uname"); if (uname == null) { log.info("*******用户名为null,非法用户,o(╥﹏╥)o"); exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE); return exchange.getResponse().setComplete(); } return chain.filter(exchange); } @Override public int getOrder() { return 0; } } ``` 说明: - 主要实现GlobalFilter、Ordered接口。 测试:访问http://127.0.0.1:9527/payment/lb?uname=xxkfz 成功访问。 ### **六、服务配置** #### **6.1、Config** springCloud Config分布式配置中心 #### 6.2、Nacos ### **七、服务总线** #### **7.1、Bus** #### **7.2、Nacos**