# 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

`学习时间 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(停更)**
项目思维导图:


#### **1.2、Zookeeper**
#### **1.3、Consul**
##### 1.3.1、Consul是什么?
官网:https://www.consul.io/docs/intro
##### 1.3.2、Consul下载安装使用
关于Consul的安装,详见Linux服务器软件安装及项目部署.docs文档!

##### 1.3.3、服务提供者注册进Consul
(1)在springcloud项目工程下面,创建模块——cloud-providerconsul-payment8006。

(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

访问:http://127.0.0.1:8500/,将会显示服务提供者cloud-providerconsul-payment8006注册进Consul。

到这里,服务提供者就完成了。
4、服务消费者注册进Consul
(1)创建服务消费者Module——cloud-consumerconsul-order80。

(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

现在访问:http://127.0.0.1:8500/,看到服务提供者:consul-provider-payment;服务消费者:cloud-consumer-order成功注册注册进Consul。

#### Nacos
### **二、服务调用**
#### **2.1、Ribbon负载均衡服务调用**
##### **2.1.1、基本概念**
Spring Cloud Ribbon是基于Netflix Ribbon实现的一套**客户端负载均衡的工具**。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供**客户端的软件负载均衡算法和服务调用**。Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等。
架构图:

如何使用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引用,因此我们不需要再需引入。

##### **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的负载规则如何替换为其他的?
基本替换步骤如下:

主要代码:
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两种间反复横跳。

##### 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之手写轮询算法**

### **三、服务调用2**
#### **3.1、OpenFeign服务接口调用**

##### **3.1.1、OpenFeign的简单使用**
1、创建Module——cloud-consumer-feign-order80

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负载均衡功能。

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。
启动完成,如下图所示:

访问:http://110.40.174.58:7001/ 可以看到,服务已经注册到Eureka上面。

访问:http://127.0.0.1/consumer/payment/get/1

##### 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

如何解决该问题呢?只需要在配置文件`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的后台日志输出,得到更多日志信息。

### **四、服务降级**
#### **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网关
网关在微服务中的位置:

Spring Cloud uolGateway的三大核心概念:
- Route路由:路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由;
- Predicate断言
- Filter过滤
**核心逻辑**:路由转发 + 执行过滤器链。

**gateway项目搭建:**
1、新建网关模块:cloud-gateway-gateway9527
项目结构如下所示:

在该模块下面主要引入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。

3、启动服务提供者:cloud-provider-payment8001。
4、测试。
添加网关之前,访问服务提供者的接口:http://localhost:8001/payment/get/1

在网关模块,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


##### **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相同的页面,效果如下:

##### **4.2.2、GateWay常用的Predicate(断言)**
###### 4.2.2.1、演示- After的使用

说明:
```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

若设置的时间为小于当前时间,访问http://127.0.0.1:9527/payment/lb

###### **4.2.2.2演示-Cookie**

说明:携带Cookie可以成功访问。
在cmd终端访问 curl http://localhost:9527/payment/lb --cookie "username=xxkfz"

不带Cookie将会访问失败。

###### **4.2.2.3、演示-Header**

说明:
```xml
- Header=X-Request-Id, \d+ # 请求头中要带有-Request-Id属性并且值为整数的正则表达式。
```
演示:在cmd终端输入:
```c
curl http://localhost:9527/payment/lb -H "X-Request-Id:123"
```
可以成功访问。

访问:
```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**