# spring-cloud-parent 学习使用spring netflix一套
**Repository Path**: toyan/spring-cloud-parent
## Basic Information
- **Project Name**: spring-cloud-parent 学习使用spring netflix一套
- **Description**: 使用eureka做注册中心
Ribbon做负载均衡
OpenFeign服务接口调用
Hystrix断路器 (豪猪)-保险丝
Gateway新一代网关
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-09-08
- **Last Updated**: 2022-09-09
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# spring-cloud-parent 学习使用spring netflix一套
## 第一章 SpringCloud简介
### 一、 软件架构演进
单体架构

垂直架构

分布式架构

SOA架构

微服务架构

### 二、微服务架构
#### 1、 微服务理念
①"微服务”一词源 于 Martin Fowler的名为 Microservices的博文,可以在他的官方博客上找到http://martinfowler.com/articles/microservices.html
②微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过 HTTP 的 RESTfuL API 进行通信协作。
**restfull 风格**:数据的增删改查,使用http的不同方式。数据传输用json。
查询 GET ip:port/user/1
新增 POST ip:port/user json{username:itlils,age:18}
修改 PUT ip:port/user/1 json{username:itlils,age:19}
删除 DELETE ip:port/user/1
③由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。大厂,各种语言混用。
cloud官网: https://spring.io/


#### 2、 现在大型互联网公司,都在使用微服务架构:
京东的促销节架构:618

阿里的架构:

京东物流的架构:

#### 3、 springcloud组件:


## 第二章 走进springcloud
### 一、了解springcloud
①Spring Cloud 是**一系列框架**的有序集合。
②Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来。
netflix eureka 1.1,alibaba 2.2
③通过 **Spring Boot** 风格进行再封装,屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
④它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、 断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
⑤Spring Cloud项目官方网址:https://spring.io/projects/spring-cloud
⑥Spring Cloud 版本命名方式采用了**伦敦地铁站的名称**,同时根据字母表的顺序来对应版本时间顺序,比如:最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,Finchley,Greenwich,Hoxton。
目前最新的是2021.0.1版本。

### 二、 cloud与boot版本对应关系

### 三、 dubbo对比

**相同点**:Spring Cloud 与 Dubbo 都是实现微服务有效的工具。
**不同点**:
1Dubbo 只是实现了服务治理,而 Spring Cloud 子项目分别覆盖了微服务架构下的众多部件。
2Dubbo 使用 RPC 通讯协议,Spring Cloud 使用 RESTful 完成通信,Dubbo 效率略高于 Spring Cloud。
**小结**
• 微服务就是将项目的各个模块拆分为可独立运行、部署、测试的架构设计风格。
• Spring 公司将其他公司中微服务架构常用的组件整合起来,并使用 SpringBoot 简化其开发、配置。称为 Spring Cloud。
• Spring Cloud 与 Dubbo都是实现微服务有效的工具。Dubbo 性能更好,而 Spring Cloud 功能更全面。Dubbo 已经融入到spingcloudAlibaba这一套
**本课程技术特点**: 两套springcloud.
1. 5年前的项目。springcloud netflix(eureka config hystrix) hoxton。会讲到。
2. 新项目 springcloud alibaba(nacos sentinel)。也会讲到。
## 第三章 停更/升级/替换
红色不维护。
绿色是alibaba一套,推荐使用。

## 第四章 微服务架构编码构建

### 一、 搭建 Provider 和 Consumer 服务
#### 1、父工程 spring-cloud-parent

使用utf-8编码

maven设置

pom.xml
```
4.0.0
com.ydlclass
spring-cloud-parent
1.0.0
org.springframework.boot
spring-boot-starter-parent
2.2.11.RELEASE
8
8
UTF-8
UTF-8
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#### 2、提供者 eureka-provider

搭建springboot工程:步骤把大象装冰箱有几步? 工作中别问同事
```
1 pom 导包
2 配置文件
3 主启动类
```
1
2
3
pom.xml
```
spring-cloud-parent
com.ydlclass
1.0.0
4.0.0
eureka-provider
8
8
org.springframework.boot
spring-boot-starter-web
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
application.yml
主启动类 ProviderApp
```
package com.ydlclass.provider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Goods
```
package com.ydlclass.provider.domain;
import java.io.Serializable;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
public class Goods implements Serializable {
private int id;//商品id
private String title;//商品名
private double price;//价格
private int count;//库存
public Goods(int id, String title, double price, int count) {
this.id = id;
this.title = title;
this.price = price;
this.count = count;
}
@Override
public String toString() {
return "Goods{" +
"id=" + id +
", title='" + title + '\'' +
", price=" + price +
", count=" + count +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
GoodsController
```
package com.ydlclass.provider.controller;
import com.ydlclass.provider.domain.Goods;
import com.ydlclass.provider.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
GoodsService goodsService;
@GetMapping("findById/{id}")
public Goods findById(@PathVariable("id") int id){
Goods goods = goodsService.findById(id);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
GoodsService
```
package com.ydlclass.provider.service;
import com.ydlclass.provider.dao.GoodsDao;
import com.ydlclass.provider.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@Service
public class GoodsService {
@Autowired
GoodsDao goodsDao;
public Goods findById(int id){
Goods goods = goodsDao.findById(id);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GoodsDao
```
package com.ydlclass.provider.dao;
import com.ydlclass.provider.domain.Goods;
import org.springframework.stereotype.Repository;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@Repository
public class GoodsDao {
public Goods findById(int id){
//查数据库
return new Goods(id,"手机",2000,100);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
**测试:**
访问:http://localhost:8000/goods/findById/1

#### 3、消费者 eureka-consumer

pom.xml
```
spring-cloud-parent
com.ydlclass
1.0-SNAPSHOT
4.0.0
eureka-consumer
org.springframework.boot
spring-boot-starter-web
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Goods
```
package com.ydlclass.consumer.domain;
/**
* 商品实体类
*/
public class Goods {
private int id;
private String title;//商品标题
private double price;//商品价格
private int count;//商品库存
public Goods() {
}
public Goods(int id, String title, double price, int count) {
this.id = id;
this.title = title;
this.price = price;
this.count = count;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
OrderController
```
package com.ydlclass.consumer.controller;
import com.ydlclass.consumer.domain.Goods;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping("/add/{id}")
public Goods add(@PathVariable("id") Integer id){
//业务逻辑
//1查询商品
//2减库存
//3支付
//4物流
return new Goods();
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
application.yml
**测试:**
http://localhost:9000/order/add/2

### 二、使用 RestTemplate 完成远程调用
- Spring提供的一种简单便捷的模板类,用于在 java 代码里访问 restful 服务。
- 其功能与 HttpClient 类似,但是 RestTemplate 实现更优雅,使用更方便。
**consumer工程中**
RestTemplateConfig
```
package com.ydlclass.consumer.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
OrderController
```
package com.ydlclass.consumer.controller;
import com.ydlclass.consumer.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 服务的调用方
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
System.out.println("findGoodsById..."+id);
/*
//远程调用Goods服务中的findOne接口
使用RestTemplate
1. 定义Bean restTemplate
2. 注入Bean
3. 调用方法
*/
String url = "http://localhost:8000/goods/findOne/"+id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
**测试:**
## 第五章 Eureka服务注册与发现
### 一、Eureka
**概念:**
• Eureka 是 Netflix 公司开源的一个服务注册与发现的组件 。
• Eureka 和其他 Netflix 公司的服务组件(例如负载均衡、熔断器、网关等) 一起,被 Spring Cloud 社区整合为Spring-Cloud-Netflix 模块。
• Eureka 包含两个组件:Eureka Server (注册中心) 和 Eureka Client (服务提供者、服务消费者)。
**操作:**

### 二、 搭建 Eureka Server 服务
(1)创建 eureka-server 模块
(2) 引入 SpringCloud 和 euraka-server 相关依赖
(3)完成 Eureka Server 相关配置
(4)启动该模块
**父工程 pom**
```
4.0.0
com.ydlclass
spring-cloud-parent
pom
1.0-SNAPSHOT
eureka-provider
eureka-consumer
eureka-server
org.springframework.boot
spring-boot-starter-parent
2.1.0.RELEASE
UTF-8
UTF-8
1.8
Greenwich.RELEASE
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
**eureka-server工程**
pom
```
spring-cloud-parent
com.ydlclass
1.0-SNAPSHOT
4.0.0
eureka-server
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
EurekaApp
```
package com.ydlclass.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
// 启用EurekaServer
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
application.yml
```
server:
port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
\*\*测试: \*\* 访问 localhost:8761

### 三、 改造 Provider 和 Consumer 称为 Eureka Client
① 引 eureka-client 相关依赖
② 完成 eureka client 相关配置
③ 启动 测试
**Provider工程**
pom
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
1
2
3
4
5
ProviderApp
application.yml
```
server:
port: 8001
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
```
1
2
3
4
5
6
7
8
9
10
11
12
13
**Consumer**
pom
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
1
2
3
4
5
ConsumerApp
```
package com.ydlclass.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
application.yml
```
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
```
1
2
3
4
5
6
7
8
9
10
11
12
### 四、 Consumer 服务 通过从 Eureka Server 中抓取 Provider 地址,完成远程调用
**Consumer**
OrderController
```
package com.ydlclass.consumer.controller;
import com.ydlclass.consumer.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/add/{id}")
public Goods add(@PathVariable("id") Integer id){
//业务逻辑
//1查询商品
//2减库存
//3支付
//4物流
//直接调用
//String url="http://localhost:8000/goods/findById/"+id;
//Goods goods = restTemplate.getForObject(url, Goods.class);
//服务发现
List instances = discoveryClient.getInstances("EUREKA-PROVIDER");
if(instances==null||instances.size()<=0){
return null;
}
//通过某个策略拿到一个实例
ServiceInstance serviceInstance = instances.get(0);
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
System.out.println(host);
System.out.println(port);
String url="http://"+host+":"+port+"/goods/findById/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
### 五、 Euraka配置详解
Eureka包含四个部分的配置
- instance:当前Eureka Instance实例信息配置
- client:Eureka Client客户端特性配置
- server:Eureka Server注册中心特性配置
- dashboard:Eureka Server注册中心仪表盘配置
#### 1、实例信息配置
```
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: # 是否将自己的ip注册到eureka中,默认false 注册 主机名
ip-address: # 设置当前实例ip
instance-id: # 修改instance-id显示
lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务
```
1
2
3
4
5
6
7
8
Eureka Instance的配置信息全部保存在org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean配置类里,实际上它是com.netflix.appinfo.EurekaInstanceConfig的实现类,替代了netflix的com.netflix.appinfo.CloudInstanceConfig的默认实现。
Eureka Instance的配置信息全部以eureka.instance.xxx的格式配置。
**配置列表**
- appname = unknown
应用名,首先获取spring.application.name的值,如果取值为空,则取默认unknown。
- appGroupName = null
应用组名
- instanceEnabledOnit = false
实例注册到Eureka上是,是否立刻开启通讯。有时候应用在准备好服务之前需要一些预处理。
- nonSecurePort = 80
非安全的端口
- securePort = 443
安全端口
- nonSecurePortEnabled = true
是否开启非安全端口通讯
- securePortEnabled = false
是否开启安全端口通讯
- leaseRenewalIntervalInSeconds = 30
实例续约间隔时间
- leaseExpirationDurationInSeconds = 90
实例超时时间,表示最大leaseExpirationDurationInSeconds秒后没有续约,Server就认为他不可用了,随之就会将其剔除。
- virtualHostName = unknown
虚拟主机名,首先获取spring.application.name的值,如果取值为空,则取默认unknown。
- instanceId
注册到eureka上的唯一实例ID,不能与相同appname的其他实例重复。
- secureVirtualHostName = unknown
安全虚拟主机名,首先获取spring.application.name的值,如果取值为空,则取默认unknown。
- metadataMap = new HashMap();
实例元数据,可以供其他实例使用。比如spring-boot-admin在监控时,获取实例的上下文和端口。
- dataCenterInfo = new MyDataCenterInfo(DataCenterInfo.Name.MyOwn);
实例部署的数据中心。如AWS、MyOwn。
- ipAddress=null
实例的IP地址
- statusPageUrlPath = "/actuator/info"
实例状态页相对url
- statusPageUrl = null
实例状态页绝对URL
- homePageUrlPath = "/"
实例主页相对URL
- homePageUrl = null
实例主页绝对URL
- healthCheckUrlUrlPath = "/actuator/health"
实例健康检查相对URL
- healthCheckUrl = null
实例健康检查绝对URL
- secureHealthCheckUrl = null
实例安全的健康检查绝对URL
- namespace = "eureka"
配置属性的命名空间(Spring Cloud中被忽略)
- hostname = null
主机名,不配置的时候讲根据操作系统的主机名来获取
- preferIpAddress = false
是否优先使用IP地址作为主机名的标识
#### 2、客户端特性配置
```
eureka:
client:
service-url:
# eureka服务端地址,将来客户端使用该地址和eureka进行通信
defaultZone:
register-with-eureka: # 是否将自己的路径 注册到eureka上。
fetch-registry: # 是否需要从eureka中抓取数据。
```
1
2
3
4
5
6
7
Eureka Client客户端特性配置是对作为Eureka客户端的特性配置,包括Eureka注册中心,本身也是一个Eureka Client。
Eureka Client特性配置全部在org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中,实际上它是com.netflix.discovery.EurekaClientConfig的实现类,替代了netxflix的默认实现。
Eureka Client客户端特性配置全部以eureka.client.xxx的格式配置。
**配置列表**
- enabled=true
是否启用Eureka client。
- registryFetchIntervalSeconds=30
定时从Eureka Server拉取服务注册信息的间隔时间
- instanceInfoReplicationIntervalSeconds=30
定时将实例信息(如果变化了)复制到Eureka Server的间隔时间。(InstanceInfoReplicator线程)
- initialInstanceInfoReplicationIntervalSeconds=40
首次将实例信息复制到Eureka Server的延迟时间。(InstanceInfoReplicator线程)
- eurekaServiceUrlPollIntervalSeconds=300
拉取Eureka Server地址的间隔时间(Eureka Server有可能增减)
- proxyPort=null
Eureka Server的代理端口
- proxyHost=null
Eureka Server的代理主机名
- proxyUserName=null
Eureka Server的代理用户名
- proxyPassword=null
Eureka Server的代理密码
- eurekaServerReadTimeoutSeconds=8
从Eureka Server读取信息的超时时间
- eurekaServerConnectTimeoutSeconds=5
连接Eureka Server的超时时间
- backupRegistryImpl=null
Eureka Client第一次启动时获取服务注册信息的调用的回溯实现。Eureka Client启动时首次会检查有没有BackupRegistry的实现类,如果有实现类,则优先从这个实现类里获取服务注册信息。
- eurekaServerTotalConnections=200
Eureka client连接Eureka Server的链接总数
- eurekaServerTotalConnectionsPerHost=50
Eureka client连接单台Eureka Server的链接总数
- eurekaServerURLContext=null
当Eureka server的列表在DNS中时,Eureka Server的上下文路径。如http://xxxx/eureka。
- eurekaServerPort=null
当Eureka server的列表在DNS中时,Eureka Server的端口。
- eurekaServerDNSName=null
当Eureka server的列表在DNS中时,且要通过DNSName获取Eureka Server列表时,DNS名字。
- region="us-east-1"
实例所属区域。
- eurekaConnectionIdleTimeoutSeconds = 30
Eureka Client和Eureka Server之间的Http连接的空闲超时时间。
- heartbeatExecutorThreadPoolSize=2
心跳(续约)执行器线程池大小。
- heartbeatExecutorExponentialBackOffBound=10
心跳执行器在续约过程中超时后的再次执行续约的最大延迟倍数。默认最大延迟时间=10 \* eureka.instance.leaseRenewalIntervalInSeconds
- cacheRefreshExecutorThreadPoolSize=2
cacheRefreshExecutord的线程池大小(获取注册信息)
- cacheRefreshExecutorExponentialBackOffBound=10
cacheRefreshExecutord的再次执行的最大延迟倍数。默认最大延迟时间=10 \*eureka.client.registryFetchIntervalSeconds
- serviceUrl= new HashMap();serviceUrl.put(DEFAULT\_ZONE, DEFAULT\_URL);
Eureka Server的分区地址。默认添加了一个defualtZone。也就是最常用的配置eureka.client.service-url.defaultZone=xxx
- registerWithEureka=true
是否注册到Eureka Server。
- preferSameZoneEureka=true
是否使用相同Zone下的Eureka server。
- logDeltaDiff=false
是否记录Eureka Server和Eureka Client之间注册信息的差异
- disableDelta=false
是否开启增量同步注册信息。
- fetchRemoteRegionsRegistry=null
获取注册服务的远程地区,以逗号隔开。
- availabilityZones=new HashMap()
可用分区列表。用逗号隔开。
- filterOnlyUpInstances = true
是否只拉取UP状态的实例。
- fetchRegistry=true
是否拉取注册信息。
- shouldUnregisterOnShutdown = true
是否在停止服务的时候向Eureka Server发起Cancel指令。
- shouldEnforceRegistrationAtInit = false
是否在初始化过程中注册服务。
#### 3、注册中心端配置
```
eureka:
server: #是否开启自我保护机制,默认true
enable-self-preservation:
eviction-interval-timer-in-ms: 120 2月#清理间隔(单位毫秒,默认是60*1000)
instance:
lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务
```
1
2
3
4
5
6
7
Eureka Server注册中心端的配置是对注册中心的特性配置。Eureka Server的配置全部在org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean里,实际上它是com.netflix.eureka.EurekaServerConfig的实现类,替代了netflix的默认实现。
Eureka Server的配置全部以eureka.server.xxx的格式进行配置。
**配置列表**
- enableSelfPreservation=true
是否开启自我保护
- renewalPercentThreshold = 0.85
自我保护续约百分比阀值因子。如果实际续约数小于续约数阀值,则开启自我保护
- renewalThresholdUpdateIntervalMs = 15 \* 60 \* 1000
续约数阀值更新频率。
- peerEurekaNodesUpdateIntervalMs = 10 \* 60 \* 1000
Eureka Server节点更新频率。
- enableReplicatedRequestCompression = false
是否启用复制请求压缩。
- waitTimeInMsWhenSyncEmpty=5 \* 60 \* 1000
当从其他节点同步实例信息为空时等待的时间。
- peerNodeConnectTimeoutMs=200
节点间连接的超时时间。
- peerNodeReadTimeoutMs=200
节点间读取信息的超时时间。
- peerNodeTotalConnections=1000
节点间连接总数。
- peerNodeTotalConnectionsPerHost = 500;
单个节点间连接总数。
- peerNodeConnectionIdleTimeoutSeconds = 30;
节点间连接空闲超时时间。
- retentionTimeInMSInDeltaQueue = 3 \* MINUTES;
增量队列的缓存时间。
- deltaRetentionTimerIntervalInMs = 30 \* 1000;
清理增量队列中过期的频率。
- evictionIntervalTimerInMs = 60 \* 1000;
剔除任务频率。
- responseCacheAutoExpirationInSeconds = 180;
注册列表缓存超时时间(当注册列表没有变化时)
- responseCacheUpdateIntervalMs = 30 \* 1000;
注册列表缓存更新频率。
- useReadOnlyResponseCache = true;
是否开启注册列表的二级缓存。
- disableDelta=false。
是否为client提供增量信息。
- maxThreadsForStatusReplication = 1;
状态同步的最大线程数。
- maxElementsInStatusReplicationPool = 10000;
状态同步队列的最大容量。
- syncWhenTimestampDiffers = true;
当时间差异时是否同步。
- registrySyncRetries = 0;
注册信息同步重试次数。
- registrySyncRetryWaitMs = 30 \* 1000;
注册信息同步重试期间的时间间隔。
- maxElementsInPeerReplicationPool = 10000;
节点间同步事件的最大容量。
- minThreadsForPeerReplication = 5;
节点间同步的最小线程数。
- maxThreadsForPeerReplication = 20;
节点间同步的最大线程数。
- maxTimeForReplication = 30000;
节点间同步的最大时间,单位为毫秒。
- disableDeltaForRemoteRegions = false;
是否启用远程区域增量。
- remoteRegionConnectTimeoutMs = 1000;
远程区域连接超时时间。
- remoteRegionReadTimeoutMs = 1000;
远程区域读取超时时间。
- remoteRegionTotalConnections = 1000;
远程区域最大连接数
- remoteRegionTotalConnectionsPerHost = 500;
远程区域单机连接数
- remoteRegionConnectionIdleTimeoutSeconds = 30;
远程区域连接空闲超时时间。
- remoteRegionRegistryFetchInterval = 30;
远程区域注册信息拉取频率。
- remoteRegionFetchThreadPoolSize = 20;
远程区域注册信息线程数。
#### 4、仪表盘配置
```
eureka:
dashboard:
enabled: true # 是否启用eureka web控制台
path: / # 设置eureka web控制台默认访问路径
```
1
2
3
4
注册中心仪表盘的配置主要是控制注册中心的可视化展示。以eureka.dashboard.xxx的格式配置。
- path="/"
仪表盘访问路径
- enabled=true
是否启用仪表盘
**改造 provider**
```
server:
port: 8001
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
**consumer**
```
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
**server**
```
server:
port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
server:
enable-self-preservation: false # 关闭自我保护机制
eviction-interval-timer-in-ms: 3000 # 检查服务的时间间隔
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
### 六、高可用

1. 准备两个Eureka Server
2. 分别进行配置,**相互注册**
3. Eureka Client 分别注册到这两个 Eureka Server中
**创建eureka-server1**
```
server:
port: 8761
eureka:
instance:
hostname: eureka-server1 # 主机名
client:
service-url:
defaultZone: http://eureka-server2:8762/eureka
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
application:
name: eureka-server-ha
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
**创建eureka-server2**
```
server:
port: 8762
eureka:
instance:
hostname: eureka-server2 # 主机名
client:
service-url:
defaultZone: http://eureka-server1:8761/eureka
register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
application:
name: eureka-server-ha
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
**修改**:C:\\Windows\\System32\\drivers\\etc\\hosts
127.0.0.1 eureka-server1 127.0.0.1 eureka-server2

测试:
provider
```
server:
port: 8001
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
client:
service-url:
defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
consumer
```
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
访问:http://localhost:9000/order/add/4

高可用测试:停掉一个eureka,依然可以访问consumer。
eureka不更新了,所以淘汰了。
## 第六章 Zookeeper服务注册与发现

有的老项目以前是dubbo,升级到微服务,使用zookeeper做注册中心。
zookeeper是一个分布式协调工具,可以实现注册中心功能。dubbo,大数据组件hadoop,hive,kafka。
**实质**:注册中心换成zk
1下载:https://zookeeper.apache.org/

zoo.cfg
```
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=F:/apache-zookeeper-3.5.6-bin/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
启动 bin目录下

2zookeeper-provider
pom
```
zookeeper-provider
org.springframework.cloud
spring-cloud-starter-zookeeper-discovery
org.apache.zookeeper
zookeeper
org.apache.zookeeper
zookeeper
3.4.9
org.slf4j
slf4j-log4j12
org.springframework.boot
spring-boot-starter-web
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
yml
```
server:
port: 8004
spring:
application:
name: zookeeper-provider
cloud:
zookeeper:
connect-string: 127.0.0.1:2181 # zk地址
```
1
2
3
4
5
6
7
8
9
主启动类
```
package com.ydlclass.zk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@SpringBootApplication
@EnableDiscoveryClient //开启发现客户端
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
业务逻辑代码直接复制粘贴过来

3zookeeper-consumer
pom
```
zookeeper-consumer
8
8
org.springframework.cloud
spring-cloud-starter-zookeeper-discovery
org.apache.zookeeper
zookeeper
org.apache.zookeeper
zookeeper
3.5.6
org.slf4j
slf4j-log4j12
org.springframework.boot
spring-boot-starter-web
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
yml
```
server:
port: 8005
spring:
application:
name: zookeeper-consumer
cloud:
zookeeper:
connect-string: 127.0.0.1:2181 # zk地址
```
1
2
3
4
5
6
7
8
9
启动类
```
package com.ydlclass.zk;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
业务逻辑代码直接复制粘贴过来

controller只改一个
```
List instances = discoveryClient.getInstances("zookeeper-provider");
```
1
测试:http://localhost:8005/order/add/5

## 第七章 Consul服务注册与发现

### 一、 是什么:
- Consul 是由 HashiCorp 基于 GoLanguage 语言开发的,支持多数据中心,分布式高可用的服务发布和注册服务软件。
- 用于实现分布式系统的服务发现与配置。
- 使用起来也较 为简单。具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署 。
- Consul官网:https://www.consul.io/ Consul中文文档:https://www.springcloud.cc/spring-cloud-consul.html
### 二、 怎么用:
#### 1、 准备


#### 2、 搭建 consul-provider
pom
```
org.springframework.cloud
spring-cloud-starter-consul-discovery
org.springframework.boot
spring-boot-starter-web
```
1
2
3
4
5
6
7
8
9
10
11
12
yml
```
server:
port: 8006
spring:
application:
name: consul-provider
cloud:
consul:
host: 127.0.0.1
port: 8500
discovery:
service-name: ${spring.application.name}
```
1
2
3
4
5
6
7
8
9
10
11
12
启动类
```
package com.ydlclass.consul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
业务逻辑复制

启动

#### 3、搭建 consul-consumer
pom
```
org.springframework.cloud
spring-cloud-starter-consul-discovery
org.springframework.boot
spring-boot-starter-web
```
1
2
3
4
5
6
7
8
9
10
11
yml
```
server:
port: 8007
spring:
application:
name: consul-consumer
cloud:
consul:
host: 127.0.0.1
port: 8500
discovery:
service-name: ${spring.application.name}
```
1
2
3
4
5
6
7
8
9
10
11
12
启动类
```
package com.ydlclass.consul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
业务逻辑复制

controller只改一句话
```
List instances = discoveryClient.getInstances("consul-provider");
```
1
启动

最终测试调用成功即可:http://localhost:8007/order/add/9

### 三、 三个注册中心的异同
| 组件 | 语言 | cap | 健康检查 | 暴露接口 | cloud集成 |
| --------- | ---- | ---- | -------- | -------- | --------- |
| eureka | java | ap | 支持 | http | 已经集成 |
| zookeeper | java | cp | 支持 | tcp | 已经集成 |
| consul | go | cp | 支持 | http | 已经集成 |
cap
- c:consustency 强一致性
- a:avalibility 可用性
- p:partition tolerance 分区容忍性
## 第八章 Ribbon负载均衡服务调用
### 一、是什么
Netflix公司推出的http和TCP的客户端负载均衡工具。
ribbon:
- 简化远程调用代码
- 内置很多负载均衡算法
#### 1、服务端负载均衡
负载均衡算法在服务端,服务端维护服务列表。

#### 2、客户端负载均衡
- 负载均衡算法在客户端
- 客户端维护服务列表

### 二、如何使用
1.新版的eureka依赖以及集成了Ribbon依赖,所以可以不引用
```
org.springframework.cloud
spring-cloud-starter-netflix-ribbon
```
1
2
3
4
5

2.声明restTemplate时@LoadBalanced
3.restTemplate请求远程服务时,ip端口替换为服务名
```
String url="http://EUREKA-PROVIDER/goods/findById/"+id;
Goods goods = restTemplate.getForObject(url, Goods.class);
```
1
2
测试:
1.启动2个provider
controller
```
goods.setTitle(goods.getTitle()+"|端口号:"+port);
```
1
idea设置 能启动两份 provider


2.多次访问consumer


多次刷新,发现:ribbon客户端,默认使用轮询算法,经行负载均衡调用。
### 三、ribbon 负载均衡策略
| **内置负载均衡规则类** | **规则描述** |
| ------------------------- | ------------------------------------------------------------ |
| RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
| AvailabilityFilteringRule | 对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。注意:可以通过修改配置loadbalancer.``.connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的``.``.ActiveConnectionsLimit属性进行配置。 |
| WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
| ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。 |
| BestAvailableRule | 忽略哪些短路的服务器,并选择并发数较低的服务器。 |
| RandomRule | 随机选择一个可用的服务器。 |
| Retry | 重试机制的选择逻辑 |
### 四、 设置ribbon 负载均衡策略
#### 1、代码
consumer工程
1.MyRule 返回想要的规则即可
```
package com.ydlclass.consumer.config;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* creste by ydlclass.itcast
*/
@Configuration
public class MyRule {
@Bean
public IRule rule(){
return new RandomRule();
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2.启动类
```
@RibbonClient(name ="EUREKA-PROVIDER",configuration = MyRule.class)
```
1
总结:
1.irule的具体实现类,看到他带的几个策略的写法。
2.仿照策略的写法,自己写策略。
3.调用不同的其他微服务时,可以采用不同的策略。
#### 2、配置
consumer工程
application.yml
```
EUREKA-PROVIDER: #远程服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #策略
```
1
2
3
作用:方便运维修改,重启。随时切换策略。
## 第九章、OpenFeign服务接口调用
### 一、概述
- Feign 是一个声明式的 REST 客户端,它用了**基于接口的注解方式**,很方便实现客户端像调用本地接口方法一样,进行远程调用。
- Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其封装,支持了SpringMVC注解,让使用者更易于接受。
- https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign
### 二、快速入门
a.在消费端引入 open-feign 依赖:
```
org.springframework.cloud
spring-cloud-starter-openfeign
```
1
2
3
4
b.编写Feign调用接口。**复制粘贴被调方的conreoller方法,加上类路径。**
GoodsFeignClient:
```
package com.ydlclass.consumer.feign;
import com.ydlclass.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@FeignClient("EUREKA-PROVIDER")
public interface GoodsFeign {
@GetMapping("/goods/findById/{id}")
public Goods findById(@PathVariable("id") Integer id);
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
c.在启动类 添加 @EnableFeignClients 注解,开启Feign功能
d.测试调用
OrderController
```
package com.ydlclass.consumer.controller;
import com.ydlclass.consumer.domain.Goods;
import com.ydlclass.consumer.feign.GoodsFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
GoodsFeign goodsFeign;
@GetMapping("/add/{id}")
public Goods add(@PathVariable("id") Integer id){
//业务逻辑
//1查询商品
//2减库存
//3支付
//4物流
//直接调用
//String url="http://localhost:8000/goods/findById/"+id;
//Goods goods = restTemplate.getForObject(url, Goods.class);
// //1服务发现
// List instances = discoveryClient.getInstances("EUREKA-PROVIDER");
// if(instances==null||instances.size()<=0){
// return null;
// }
// //2通过某个策略拿到一个实例 算法
// ServiceInstance serviceInstance = instances.get(0);
// String host = serviceInstance.getHost();
// int port = serviceInstance.getPort();
// System.out.println(host);
// System.out.println(port);
//
// String url="http://"+host+":"+port+"/goods/findById/"+id;
// Goods goods = restTemplate.getForObject(url, Goods.class);
//ribbon
// String url="http://EUREKA-PROVIDER/goods/findById/"+id;
// Goods goods = restTemplate.getForObject(url, Goods.class);
//feign调用
Goods goods = goodsFeign.findById(id);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
### 三、其他设置
#### 1、超时设置
• Feign 底层依赖于 Ribbon 实现负载均衡和远程调用

• Ribbon默认1秒超时。
• 超时配置: yml中
```
# 设置Ribbon的超时时间
ribbon:
ConnectTimeout: 1000 # 连接超时时间 默认1s
ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s
```
1
2
3
4
测试:
1.连接超时,provider都停掉

2.逻辑处理的超时时间
provider
```
@GetMapping("/findById/{id}")
public Goods findById(@PathVariable("id") Integer id){
Goods goods = goodsService.findById(id);
goods.setTitle(goods.getTitle()+"|端口号:"+port);
//模拟业务逻辑比较繁忙
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return goods;
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13

#### 2、日志记录
1.Feign 只能记录 debug 级别的日志信息。
```
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
com.ydlclass: debug
```
1
2
3
4
• 定义Feign日志级别Bean
FeignLogConfig
```
package com.ydlclass.consumer.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignLogConfig {
/*
NONE,不记录
BASIC,记录基本的请求行,响应状态码数据
HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
FULL;记录完成的请求 响应数据
*/
@Bean
public Logger.Level level(){
return Logger.Level.FULL;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
3. 启用该Bean:
GoodsFeignClient
```
@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)
```
1
## 
设置为headers

## 第十章 Hystrix断路器 (豪猪)-保险丝
### 一、概述
重点:能让服务的调用方,够快的知道被调方挂了!不至于说让用户在等待。
Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。
雪崩:一个服务失败,导致整条链路的服务都失败的情形。




**Hystix 主要功能**

**隔离**
1. 线程池隔离
没有hystrix,a重试100次,才知道c挂了!

使用了hystrix,更细分线程池,只需要重试40次,让a更快的知道c挂了

2. 信号量隔离
没有hystrix,a一个带着认证信息的线程,重试100次,才知道c挂了!

使用了hystrix,更细分线程池,一个带着认证信息的线程,只需要重试40次,让a更快的知道c挂了

**降级**:
服务提供方降级(异常,超时)

消费方降级

**熔断**
**限流**
是有限流,但是,项目一般不用。nginx或者网关限流。
### 二、服务降级
**服务提供方**
a、在服务提供方,引入 hystrix 依赖
```
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
```
1
2
3
4
5
b、方法
```
/** 定义降级方法 返回特殊对象
* 1方法的返回值要和原方法一致
* 2方法参数和原方法一样
*/
public Goods findById_fallback(Integer id){
Goods goods=new Goods();
goods.setGoodId(-1);
goods.setTitle("provider提供方降级!");
goods.setPrice(-9.9);
goods.setStock(-10);
return goods;
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
c、使用 @HystrixCommand 注解配置降级方法
```
@GetMapping("/findById/{id}")
@HystrixCommand(fallbackMethod = "findById_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findById(@PathVariable("id") Integer id){
Goods goods = goodsService.findById(id);
goods.setTitle(goods.getTitle()+"|端口号:"+port);
//模拟出异常
// int a=1/0;
//模拟业务逻辑比较繁忙
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return goods;
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
d、在启动类上开启Hystrix功能:@EnableCircuitBreaker
测试:http://localhost:9000/order/add/10
1.出错,服务方降级了

2.3000超时,服务方降级了

**服务消费方**
a、feign 组件已经集成了 hystrix 组件。
b、

c、定义feign 调用接口实现类,复写方法,即 降级方法
GoodsFeignClientFallback
```
package com.ydlclass.consumer.feign;
import com.ydlclass.consumer.domain.Goods;
import org.springframework.stereotype.Component;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@Component
public class GoodsFeignCallback implements GoodsFeign{
@Override
public Goods findById(Integer id) {
Goods goods=new Goods();
goods.setGoodId(-2);
goods.setTitle("调用方降级了!");
goods.setPrice(-5.5);
goods.setStock(-5);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
d、在 @FeignClient 注解中使用 fallback 属性设置降级处理类。
GoodsFeignClient
```
package com.ydlclass.consumer.feign;
import com.ydlclass.consumer.config.FeignLogConfig;
import com.ydlclass.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class,fallback = GoodsFeignCallback.class)
public interface GoodsFeign {
@GetMapping("/goods/findById/{id}")
public Goods findById(@PathVariable("id") Integer id);
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
e、配置开启
```
# 开启feign对hystrix的支持
feign:
hystrix:
enabled: true
```
1
2
3
4
测试:停掉provider
http://localhost:9000/order/add/10

### 三、熔断

测试:
provider
```
package com.ydlclass.proviver.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.ydlclass.proviver.domain.Goods;
import com.ydlclass.proviver.service.GoodsService;
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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@Autowired
GoodsService goodsService;
@Value("${server.port}")
int port;
@GetMapping("/findById/{id}")
@HystrixCommand(fallbackMethod = "findById_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
public Goods findById(@PathVariable("id") Integer id){
Goods goods = goodsService.findById(id);
goods.setTitle(goods.getTitle()+"|端口号:"+port);
if(id==1){
//模拟出异常
int a=1/0;
}
//模拟出异常
// int a=1/0;
//模拟业务逻辑比较繁忙
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
return goods;
}
/** 定义降级方法 返回特殊对象
* 1方法的返回值要和原方法一致
* 2方法参数和原方法一样
*/
public Goods findById_fallback(Integer id){
Goods goods=new Goods();
goods.setGoodId(-1);
goods.setTitle("provider提供方降级!");
goods.setPrice(-9.9);
goods.setStock(-10);
return goods;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
访问两个接口
1. http://localhost:9000/order/add/10

2. 多次访问 http://localhost:9000/order/add/1

3.导致10也不能访问了

4.再过一会儿,半开状态
http://localhost:9000/order/add/10

Hyst rix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。
```
circuitBreaker.sleepWindowInMilliseconds:监控时间
circuitBreaker.requestVolumeThreshold:失败次数
circuitBreaker.errorThresholdPercentage:失败率
```
1
2
3
提供者controller中
```
@HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
//设置Hystrix的超时时间,默认1s
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
//监控时间 默认5000 毫秒
@HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
//失败次数。默认20次
@HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
//失败率 默认50%
@HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")
})
```
1
2
3
4
5
6
7
8
9
10
11
### 四、熔断监控\*\*-运维

Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。
但是Hystrix-dashboard只能监控一个微服务。
Netflix 还提供了 Turbine ,进行聚合监控。

**Turbine聚合监控**
#### 1、搭建监控模块
**a、 创建监控模块**
创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能,
**b、引入Turbine聚合监控起步依赖**
```
spring-cloud-parent
com.ydlclass
1.0.0
4.0.0
hystrix-monitor
8
8
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
org.springframework.cloud
spring-cloud-starter-netflix-turbine
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
**d、修改application.yml**
```
spring:
application:
name: hystrix-monitor
server:
port: 8769
turbine:
combine-host-port: true
# 配置需要监控的服务名称列表
app-config: EUREKA-PROVIDER,EUREKA-CONSUMER
cluster-name-expression: "'default'"
aggregator:
cluster-config: default
#instanceUrlSuffix: /actuator/hystrix.stream
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
hystrix:
dashboard:
proxy-stream-allow-list: "*"
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
**e、创建启动类**
```
package com.ydlclass.monitor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.turbine.EnableTurbine;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@SpringBootApplication
@EnableEurekaClient
@EnableTurbine //开启Turbine 很聚合监控功能
@EnableHystrixDashboard //开启Hystrix仪表盘监控功能
public class HystrixMonitorApp {
public static void main(String[] args) {
SpringApplication.run(HystrixMonitorApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#### 2、修改被监控模块
需要分别修改 hystrix-provider 和 hystrix-consumer 模块:
**a、导入依赖:**
```
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
**b、配置Bean**
此处为了方便,将其配置在启动类中。
```
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
```
1
2
3
4
5
6
7
8
9
**c、启动类上添加注解@EnableHystrixDashboard**
```
@EnableDiscoveryClient
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@EnableHystrixDashboard // 开启Hystrix仪表盘监控功能
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#### 3、启动测试
**a、启动服务:**
- eureka-server
- hystrix-provider
- hystrix-consumer
- hystrix-monitor
**b、访问:**
在浏览器访问http://localhost:8769/hystrix/ 进入Hystrix Dashboard界面

界面中输入监控的Url地址 http://localhost:8769/turbine.stream,监控时间间隔2000毫秒和title,如下图

- 实心圆:它有颜色和大小之分,分别代表实例的监控程度和流量大小。如上图所示,它的健康度从绿色、黄色、橙色、红色递减。通过该实心圆的展示,我们就可以在大量的实例中快速的发现故障实例和高压力实例。
- 曲线:用来记录 2 分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。
## 第十一章、zuul路由网关
zuul核心人员走了两个,zuul2的研发过久,spring公司等不及,自己研发的Gateway网关。
https://github.com/Netflix/zuul/wiki
## 第十二章 Gateway新一代网关
功能:路由+过滤
### 一、 **概述**
https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/
不使用
存在的问题:
```
解决缺点:1客户端需要记录不同微服务地址,增加客户端的复杂性
2每个后台微服务都需要认证
3http 发请求,涉及到跨域
4后台新增微服务,不能动态知道地址
```
1
2
3
4

使用了网关的话:
• 网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
• 在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。
• 网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
• 在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul/zuul2 、Spring Cloud Gateway等等

### 二、 **快速入门**
(1)搭建网关模块 api-gateway-server
(2)引入依赖:starter-gateway
```
gateway-parent
com.ydlclass
1.0-SNAPSHOT
4.0.0
api-gateway-server
org.springframework.cloud
spring-cloud-starter-gateway
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
(3)编写启动类
ApiGatewayApp
```
package com.ydlclass.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(4)编写配置文件
```
server:
port: 80
spring:
application:
name: api-gateway-server
cloud:
# 网关配置
gateway:
# 路由配置:转发规则
routes: #集合。
# id: 唯一标识。默认是一个UUID
# uri: 转发路径
# predicates: 条件,用于请求网关路径的匹配规则
# filters:配置局部过滤器的
- id: eureka-provider
# 静态路由
# uri: http://localhost:8001/
# 动态路由
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters:
- AddRequestParameter=username,zhangsan
- id: eureka-consumer
# uri: http://localhost:9000
uri: lb://GATEWAY-CONSUMER
predicates:
- Path=/order/**
# 微服务名称配置
discovery:
locator:
enabled: true # 设置为true 请求路径前可以添加微服务名称
lower-case-service-id: true # 允许为小写
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
(5)启动测试
http://localhost/goods/findById/2


### 三、 **静态路由**
```
uri: http://localhost:8000/
```
1
### 四、**动态路由**

#### 1、引入eureka-client配置
pom
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
1
2
3
4
yml
```
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
```
1
2
3
4
#### 2、修改uri属性:uri: lb://服务名称
```
uri: lb://eureka-provider
```
1
测试:
http://localhost/goods/findById/2

### 五、微服务名称配置\*\*
```
spring:
cloud:
# 网关配置
gateway:
# 微服务名称配置
discovery:
locator:
enabled: true # 设置为true 请求路径前可以添加微服务名称
lower-case-service-id: true # 允许为小写
```
1
2
3
4
5
6
7
8
9
测试:http://localhost/eureka-provider/goods/findById/2

### 六、过滤器
(1)两个维度:
内置过滤器 自定义过滤器
局部过滤器 全局过滤器
(2)过滤器种类:
内置局部过滤器
内置全局过滤器
自定义局部过滤器
自定义全局过滤器

- Gateway 支持过滤器功能,对请求或响应进行拦截,完成一些通用操作。
- Gateway 提供两种过滤器方式:“pre”和“post”
```
pre 过滤器,在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换等。
post 过滤器,在响应之前执行,可以做响应内容、响应头的修改,日志的输出,流量监控等。
```
1
2
- Gateway 还提供了两种类型过滤器
```
GatewayFilter:局部过滤器,针对单个路由
GlobalFilter :全局过滤器,针对所有路由
```
1
2
内置过滤器 局部过滤器:
```
- id: gateway-provider
#uri: http://localhost:8001/
uri: lb://GATEWAY-PROVIDER
predicates:
- Path=/goods/**
filters:
- AddResponseHeader=foo, bar
```
1
2
3
4
5
6
7

内置过滤器 全局过滤器: route同级
```
default-filters:
- AddResponseHeader=yld,itlils
```
1
2


**拓展:**
内置的过滤器工厂
这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格。如下:
| 过滤器工厂 | 作用 | 参数 |
| --------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| AddRequestHeader | 为原始请求添加Header | Header的名称及值 |
| AddRequestParameter | 为原始请求添加请求参数 | 参数名称及值 |
| AddResponseHeader | 为原始响应添加Header | Header的名称及值 |
| DedupeResponseHeader | 剔除响应头中重复的值 | 需要去重的Header名称及去重策略 |
| Hystrix | 为路由引入Hystrix的断路器保护 | `HystrixCommand`的名称 |
| FallbackHeaders | 为fallbackUri的请求头中添加具体的异常信息 | Header的名称 |
| PrefixPath | 为原始请求路径添加前缀 | 前缀路径 |
| PreserveHostHeader | 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host | 无 |
| RequestRateLimiter | 用于对请求限流,限流算法为令牌桶 | keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus |
| RedirectTo | 将原始请求重定向到指定的URL | http状态码及重定向的url |
| RemoveHopByHopHeadersFilter | 为原始请求删除IETF组织规定的一系列Header | 默认就会启用,可以通过配置指定仅删除哪些Header |
| RemoveRequestHeader | 为原始请求删除某个Header | Header名称 |
| RemoveResponseHeader | 为原始响应删除某个Header | Header名称 |
| RewritePath | 重写原始的请求路径 | 原始路径正则表达式以及重写后路径的正则表达式 |
| RewriteResponseHeader | 重写原始响应中的某个Header | Header名称,值的正则表达式,重写后的值 |
| SaveSession | 在转发请求之前,强制执行`WebSession::save`操作 | 无 |
| secureHeaders | 为原始响应添加一系列起安全作用的响应头 | 无,支持修改这些安全响应头的值 |
| SetPath | 修改原始的请求路径 | 修改后的路径 |
| SetResponseHeader | 修改原始响应中某个Header的值 | Header名称,修改后的值 |
| SetStatus | 修改原始响应的状态码 | HTTP 状态码,可以是数字,也可以是字符串 |
| StripPrefix | 用于截断原始请求的路径 | 使用数字表示要截断的路径的数量 |
| Retry | 针对不同的响应进行重试 | retries、statuses、methods、series |
| RequestSize | 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 `413 Payload Too Large` | 请求包大小,单位为字节,默认值为5M |
| ModifyRequestBody | 在转发请求之前修改原始请求体内容 | 修改后的请求体内容 |
| ModifyResponseBody | 修改原始响应体的内容 | 修改后的响应体内容 |
| Default | 为所有路由添加过滤器 | 过滤器工厂名称及值 |
\*\*Tips:\*\*每个过滤器工厂都对应一个实现类,并且这些类的名称必须以`GatewayFilterFactory`结尾,这是Spring Cloud Gateway的一个约定,例如`AddRequestHeader`对应的实现类为`AddRequestHeaderGatewayFilterFactory`。
___
1、AddRequestHeader GatewayFilter Factory
为原始请求添加Header,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
- AddRequestHeader=X-Request-Foo, Bar
```
1
2
3
4
5
6
7
8
为原始请求添加名为 `X-Request-Foo` ,值为 `Bar` 的请求头
2、AddRequestParameter GatewayFilter Factory
为原始请求添加请求参数及值,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=foo, bar
```
1
2
3
4
5
6
7
8
为原始请求添加名为foo,值为bar的参数,即:`foo=bar`
3、AddResponseHeader GatewayFilter Factory
为原始响应添加Header,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Foo, Bar
```
1
2
3
4
5
6
7
8
为原始响应添加名为 `X-Request-Foo` ,值为 `Bar` 的响应头
4、DedupeResponseHeader GatewayFilter Factory
DedupeResponseHeader可以根据配置的Header名称及去重策略剔除响应头中重复的值,这是Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。
我们在Gateway以及微服务上都设置了CORS(解决跨域)Header的话,如果不做任何配置,那么请求 -> 网关 -> 微服务,获得的CORS Header的值,就将会是这样的:
```
Access-Control-Allow-Credentials: true, true
Access-Control-Allow-Origin: https://musk.mars, https://musk.mars
```
1
2
可以看到这两个Header的值都重复了,若想把这两个Header的值去重的话,就需要使用到DedupeResponseHeader,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: dedupe_response_header_route
uri: https://example.org
filters:
# 若需要去重的Header有多个,使用空格分隔
- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
```
1
2
3
4
5
6
7
8
9
去重策略:
- RETAIN\_FIRST:默认值,保留第一个值
- RETAIN\_LAST:保留最后一个值
- RETAIN\_UNIQUE:保留所有唯一值,以它们第一次出现的顺序保留
若想对该过滤器工厂有个比较全面的了解的话,建议阅读该过滤器工厂的源码,因为源码里有详细的注释及示例,比官方文档写得还好:`org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory`
5、Hystrix GatewayFilter Factory
为路由引入Hystrix的断路器保护,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: hystrix_route
uri: https://example.org
filters:
- Hystrix=myCommandName
```
1
2
3
4
5
6
7
8
Hystrix是Spring Cloud第一代容错组件,不过已经进入维护模式,未来Hystrix会被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J。所以本文不做详细介绍了,感兴趣的话可以参考官方文档:
- [Hystrix GatewayFilter Factoryopen in new window](https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#hystrix)
6、FallbackHeaders GatewayFilter Factory
同样是对Hystrix的支持,上一小节所介绍的过滤器工厂支持一个配置参数:`fallbackUri`,该配置用于当发生异常时将请求转发到一个特定的uri上。而`FallbackHeaders`这个过滤工厂可以在转发请求到该uri时添加一个Header,这个Header的值为具体的异常信息。配置示例:
```
spring:
cloud:
gateway:
routes:
- id: ingredients
uri: lb://ingredients
predicates:
- Path=//ingredients/**
filters:
- name: Hystrix
args:
name: fetchIngredients
fallbackUri: forward:/fallback
- id: ingredients-fallback
uri: http://localhost:9994
predicates:
- Path=/fallback
filters:
- name: FallbackHeaders
args:
executionExceptionTypeHeaderName: Test-Header
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
这里也不做详细介绍了,感兴趣可以参考官方文档:
- [FallbackHeaders GatewayFilter Factoryopen in new window](https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#fallback-headers)
7、PrefixPath GatewayFilter Factory
为原始的请求路径添加一个前缀路径,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
```
1
2
3
4
5
6
7
8
该配置使访问`${GATEWAY_URL}/hello` 会转发到`https://example.org/mypath/hello`
8、PreserveHostHeader GatewayFilter Factory
为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host Header。配置示例:
```
spring:
cloud:
gateway:
routes:
- id: preserve_host_route
uri: https://example.org
filters:
- PreserveHostHeader
```
1
2
3
4
5
6
7
8
如果不设置,那么名为 `Host` 的Header将由Http Client控制
9、RequestRateLimiter GatewayFilter Factory
用于对请求进行限流,限流算法为令牌桶。配置示例:
```
spring:
cloud:
gateway:
routes:
- id: requestratelimiter_route
uri: https://example.org
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
```
1
2
3
4
5
6
7
8
9
10
11
由于另一篇文章中已经介绍过如何使用该过滤器工厂实现网关限流,所以这里就不再赘述了:
- [Spring Cloud Gateway - 扩展open in new window](https://blog.51cto.com/zero01/2430532)
或者参考官方文档:
- [RequestRateLimiter GatewayFilter Factoryopen in new window](https://cloud.spring.io/spring-cloud-static/Greenwich.SR2/single/spring-cloud.html#_requestratelimiter_gatewayfilter_factory)
10、RedirectTo GatewayFilter Factory
将原始请求重定向到指定的Url,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: redirect_route
uri: https://example.org
filters:
- RedirectTo=302, https://acme.org
```
1
2
3
4
5
6
7
8
该配置使访问 `${GATEWAY_URL}/hello` 会被重定向到 `https://acme.org/hello` ,并且携带一个 `Location:http://acme.org` 的Header,而返回客户端的HTTP状态码为302
注意事项:
- HTTP状态码应为3xx,例如301
- URL必须是合法的URL,该URL会作为`Location` Header的值
11、RemoveHopByHopHeadersFilter GatewayFilter Factory
为原始请求删除[IETFopen in new window](https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.3)组织规定的一系列Header,默认删除的Header如下:
- Connection
- Keep-Alive
- Proxy-Authenticate
- Proxy-Authorization
- TE
- Trailer
- Transfer-Encoding
- Upgrade
可以通过配置去指定仅删除哪些Header,配置示例:
```
spring:
cloud:
gateway:
filter:
remove-hop-by-hop:
# 多个Header使用逗号(,)分隔
headers: Connection,Keep-Alive
```
1
2
3
4
5
6
7
12、RemoveRequestHeader GatewayFilter Factory
为原始请求删除某个Header,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: removerequestheader_route
uri: https://example.org
filters:
- RemoveRequestHeader=X-Request-Foo
```
1
2
3
4
5
6
7
8
删除原始请求中名为 `X-Request-Foo` 的请求头
13、RemoveResponseHeader GatewayFilter Factory
为原始响应删除某个Header,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: removeresponseheader_route
uri: https://example.org
filters:
- RemoveResponseHeader=X-Response-Foo
```
1
2
3
4
5
6
7
8
删除原始响应中名为 `X-Request-Foo` 的响应头
14、RewritePath GatewayFilter Factory
通过正则表达式重写原始的请求路径,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://example.org
predicates:
- Path=/foo/**
filters:
# 参数1为原始路径的正则表达式,参数2为重写后路径的正则表达式
- RewritePath=/foo/(?.*), /$\{segment}
```
1
2
3
4
5
6
7
8
9
10
11
12
该配置使得访问 `/foo/bar` 时,会将路径重写为`/bar` 再进行转发,也就是会转发到 `https://example.org/bar`。需要注意的是:由于YAML语法,需用`$\` 替换 `$`
15、RewriteResponseHeader GatewayFilter Factory
重写原始响应中的某个Header,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: rewriteresponseheader_route
uri: https://example.org
filters:
# 参数1为Header名称,参数2为值的正则表达式,参数3为重写后的值
- RewriteResponseHeader=X-Response-Foo, password=[^&]+, password=***
```
1
2
3
4
5
6
7
8
9
10
该配置的意义在于:如果响应头中 `X-Response-Foo` 的值为`/42?user=ford&password=omg!what&flag=true`,那么就会被按照配置的值重写成`/42?user=ford&password=***&flag=true`,也就是把其中的`password=omg!what`重写成了`password=***`
16、SaveSession GatewayFilter Factory
在转发请求之前,强制执行`WebSession::save`操作,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: save_session
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- SaveSession
```
1
2
3
4
5
6
7
8
9
10
11
主要用在那种像 Spring Session 延迟数据存储(数据不是立刻持久化)的,并希望在请求转发前确保session状态保存情况。如果你将Spring Secutiry于Spring Session集成使用,并想确保安全信息都传到下游机器,你就需要配置这个filter。
17、secureHeaders GatewayFilter Factory
secureHeaders过滤器工厂主要是参考了[这篇博客open in new window](https://blog.appcanary.com/2017/http-security-headers.html)中的建议,为原始响应添加了一系列起安全作用的响应头。默认会添加如下Headers(包括值):
- `X-Xss-Protection:1; mode=block`
- `Strict-Transport-Security:max-age=631138519`
- `X-Frame-Options:DENY`
- `X-Content-Type-Options:nosniff`
- `Referrer-Policy:no-referrer`
- `Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'`
- `X-Download-Options:noopen`
- `X-Permitted-Cross-Domain-Policies:none`
如果你想修改这些Header的值,那么就需要使用这些Headers对应的后缀,如下:
- `xss-protection-header`
- `strict-transport-security`
- `frame-options`
- `content-type-options`
- `referrer-policy`
- `content-security-policy`
- `download-options`
- `permitted-cross-domain-policies`
配置示例:
```
spring:
cloud:
gateway:
filter:
secure-headers:
# 修改 X-Xss-Protection 的值为 2; mode=unblock
xss-protection-header: 2; mode=unblock
```
1
2
3
4
5
6
7
如果想禁用某些Header,可使用如下配置:
```
spring:
cloud:
gateway:
filter:
secure-headers:
# 多个使用逗号(,)分隔
disable: frame-options,download-options
```
1
2
3
4
5
6
7
8
18、SetPath GatewayFilter Factory
修改原始的请求路径,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: setpath_route
uri: https://example.org
predicates:
- Path=/foo/{segment}
filters:
- SetPath=/{segment}
```
1
2
3
4
5
6
7
8
9
10
11
该配置使访问 `${GATEWAY_URL}/foo/bar` 时会转发到 `https://example.org/bar` ,也就是原本的`/foo/bar`被修改为了`/bar`
19、SetResponseHeader GatewayFilter Factory
修改原始响应中某个Header的值,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: setresponseheader_route
uri: https://example.org
filters:
- SetResponseHeader=X-Response-Foo, Bar
```
1
2
3
4
5
6
7
8
9
将原始响应中 `X-Response-Foo` 的值修改为 `Bar`
20、SetStatus GatewayFilter Factory
修改原始响应的状态码,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: setstatusstring_route
uri: https://example.org
filters:
# 字符串形式
- SetStatus=BAD_REQUEST
- id: setstatusint_route
uri: https://example.org
filters:
# 数字形式
- SetStatus=401
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
SetStatusd的值可以是数字,也可以是字符串。但一定要是Spring `HttpStatus` 枚举类中的值。上面这两种配置都可以返回401这个HTTP状态码。
21、StripPrefix GatewayFilter Factory
用于截断原始请求的路径,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: http://nameservice
predicates:
- Path=/name/**
filters:
# 数字表示要截断的路径的数量
- StripPrefix=2
```
1
2
3
4
5
6
7
8
9
10
11
12
如上配置,如果请求的路径为 `/name/bar/foo` ,那么则会截断成`/foo`后进行转发 ,也就是会截断2个路径。
22、Retry GatewayFilter Factory
针对不同的响应进行重试,例如可以针对HTTP状态码进行重试,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: retry_test
uri: http://localhost:8080/flakey
predicates:
- Host=*.retry.com
filters:
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
```
1
2
3
4
5
6
7
8
9
10
11
12
13
可配置如下参数:
- `retries`:重试次数
- `statuses`:需要重试的状态码,取值在 `org.springframework.http.HttpStatus` 中
- `methods`:需要重试的请求方法,取值在 `org.springframework.http.HttpMethod` 中
- `series`:HTTP状态码序列,取值在 `org.springframework.http.HttpStatus.Series` 中
23、RequestSize GatewayFilter Factory
设置允许接收最大请求包的大小,配置示例:
```
spring:
cloud:
gateway:
routes:
- id: request_size_route
uri: http://localhost:8080/upload
predicates:
- Path=/upload
filters:
- name: RequestSize
args:
# 单位为字节
maxSize: 5000000
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
如果请求包大小超过设置的值,则会返回 `413 Payload Too Large`以及一个`errorMessage`
24、Modify Request Body GatewayFilter Factory
在转发请求之前修改原始请求体内容,该过滤器工厂只能通过代码配置,不支持在配置文件中配置。代码示例:
```
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
.build();
}
static class Hello {
String message;
public Hello() { }
public Hello(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
> Tips:该过滤器工厂处于 **BETA** 状态,未来API可能会变化,生产环境请慎用
25、Modify Response Body GatewayFilter Factory
可用于修改原始响应体的内容,该过滤器工厂同样只能通过代码配置,不支持在配置文件中配置。代码示例:
```
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyResponseBody(String.class, String.class,
(exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
.build();
}
```
1
2
3
4
5
6
7
8
9
10
> Tips:该过滤器工厂处于 **BETA** 状态,未来API可能会变化,生产环境请慎用
26、Default Filters
Default Filters用于为所有路由添加过滤器工厂,也就是说通过Default Filter所配置的过滤器工厂会作用到所有的路由上。配置示例:
```
spring:
cloud:
gateway:
default-filters:
- AddResponseHeader=X-Response-Default-Foo, Default-Bar
- PrefixPath=/httpbin
```
1
2
3
4
5
6
___
官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-cloud-gateway.html#\_gatewayfilter\_factories
#### 自定义过滤器
1、自定义 局部过滤器
麻烦,很少。
```
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.cloud.gateway.filter.factory;
import java.util.Arrays;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.GatewayToStringStyler;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
public class StripPrefixGatewayFilterFactory extends AbstractGatewayFilterFactory {
public static final String PARTS_KEY = "parts";
public StripPrefixGatewayFilterFactory() {
super(StripPrefixGatewayFilterFactory.Config.class);
}
public List shortcutFieldOrder() {
return Arrays.asList("parts");
}
public GatewayFilter apply(StripPrefixGatewayFilterFactory.Config config) {
return new GatewayFilter() {
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerWebExchangeUtils.addOriginalRequestUrl(exchange, request.getURI());
String path = request.getURI().getRawPath();
String[] originalParts = StringUtils.tokenizeToStringArray(path, "/");
StringBuilder newPath = new StringBuilder("/");
for(int i = 0; i < originalParts.length; ++i) {
if (i >= config.getParts()) {
if (newPath.length() > 1) {
newPath.append('/');
}
newPath.append(originalParts[i]);
}
}
if (newPath.length() > 1 && path.endsWith("/")) {
newPath.append('/');
}
ServerHttpRequest newRequest = request.mutate().path(newPath.toString()).build();
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate().request(newRequest).build());
}
public String toString() {
return GatewayToStringStyler.filterToStringCreator(StripPrefixGatewayFilterFactory.this).append("parts", config.getParts()).toString();
}
};
}
public static class Config {
private int parts;
public Config() {
}
public int getParts() {
return this.parts;
}
public void setParts(int parts) {
this.parts = parts;
}
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
2、自定义 全局过滤器
需求:1黑客ip,直接给你拒接掉。
2某些请求路径 如“goods/findById”,危险操作,记录日志。
自定义全局过滤器步骤:
```
1. 定义类实现 GlobalFilter 和 Ordered接口
2. 复写方法
3. 完成逻辑处理
```
1
2
3
IpFilter
```
package com.ydlclass.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.net.InetAddress;
import java.net.InetSocketAddress;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@Component
public class IpFilter implements GlobalFilter, Ordered {
//写业务逻辑
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//1黑客ip,直接给你拒接掉。
//拿到请求和响应,为所欲为
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
InetSocketAddress remoteAddress = request.getRemoteAddress();
String hostName = remoteAddress.getHostName();
System.out.println(hostName);
InetAddress address = remoteAddress.getAddress();
String hostAddress = address.getHostAddress();
System.out.println(hostAddress);
String hostName1 = address.getHostName();
System.out.println(hostName1);
if (hostAddress.equals("192.168.31.11")) {
//拒绝
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.setComplete();
}
//走完了,该到下一个过滤器了
return chain.filter(exchange);
}
//返回数值,越小越先执行
@Override
public int getOrder() {
return 0;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
UrlFilter
```
package com.ydlclass.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.net.URI;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@Component
public class UrlFilter implements GlobalFilter, Ordered {
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//某些请求路径 如“goods/findById”,危险操作,记录日志。
//拿到请求和响应,为所欲为
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
URI uri = request.getURI();
String path = uri.getPath();
System.out.println(path);
if(path.contains("goods/findById")){
//打日志
System.out.println("path很危险!");
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return 1;
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
测试:
1、ipfilter

把自己的ip设置为拒绝访问的话

2、

## 第十三章 分布式配置中心
13-16组件,超大型公司才会用到
国内BATJ,或者国外FLAG:facebook linkedin amazon google
处理大规模微服务的技术。
### 一、Config 概述

Spring Cloud Config 解决了在分布式场景下多环境配置文件的管理和维护。
好处:
• 集中管理配置文件
• 不同环境不同配置,动态化的配置更新
• 配置信息改变时,不需要重启即可更新配置信息到服务
### 二、Config 快速入门

**config-server:**
1. 使用gitee创建远程仓库,上传配置文件
config-dev.yml
2. 搭建 config-server 模块
ConfigServerApp
```
package com.ydlclass.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer // 启用config server功能
public class ConfigServerApp {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
3. 导入 config-server 依赖
pom
```
org.springframework.cloud
spring-cloud-config-server
```
1
2
3
4
5
4. 编写配置,设置 gitee 远程仓库地址
application.yml
```
server:
port: 9527
spring:
application:
name: config-server
# spring cloud config
cloud:
config:
server:
# git 的 远程仓库地址
git:
uri: https://gitee.com/ydlclass_cch/ydlclass-configs.git
label: master # 分支配置
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
5. 测试访问远程配置文件
http://localhost:9527/master/provider-dev.yml

**config-client:** provider
1. 导入 starter-config 依赖
```
org.springframework.cloud
spring-cloud-starter-config
```
1
2
3
4
5
2. 配置config server 地址,读取配置文件名称等信息
bootstrap.yml
```
# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
cloud:
config:
# 配置config-server地址
uri: http://localhost:9527
# 配置获得配置文件的名称等信息
name: provider # 文件名
profile: dev # profile指定, config-dev.yml
label: master # 分支
```
1
2
3
4
5
6
7
8
9
10
11
3. 获取配置值
GoodsController
```
@Value("${ydlclass}")
private String ydlclass;
goods.setTitle(goods.getTitle()+"|端口号:"+port+"|ydlclass"+ydlclass);
```
1
2
3
4
4. 启动测试
http://localhost:8000/goods/findById/9

**Config 客户端刷新**

1. 在 config 客户端引入 actuator 依赖
```
org.springframework.boot
spring-boot-starter-actuator
```
1
2
3
4
2. 获取配置信息类上,添加 @RefreshScope 注解
GoodsController
```
@RefreshScope // 开启刷新功能
```
1
3. 添加配置
bootstrap.yml
```
management:
endpoints:
web:
exposure:
include: '*'
```
1
2
3
4
5
4. 使用curl工具发送post请求
curl -X POST http://localhost:8000/actuator/refresh

测试: 值已经变了

### 三、Config 集成Eureka

**config-client配置:**
pom
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
1
2
3
4
5
ProviderApp
bootstrap.yml
```
# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
cloud:
config:
# 配置config-server地址
#uri: http://localhost:9527
# 配置获得配置文件的名称等信息
name: config # 文件名
profile: dev # profile指定, config-dev.yml
label: master # 分支
discovery:
enabled: true
service-id: CONFIG-SERVER
management:
endpoints:
web:
exposure:
include: '*'
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
**config-server配置:**
pom
```
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
```
1
2
3
4
5
ConfigServerApp
application.yml
```
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
```
1
2
3
4
测试:

## 第十四章 SpringCloud Bus消息总线
远程的配置文件更新了,运维只需要发一个请求,所有用到这个配置文件的几百个应用更新了。
### 一、Bus 概述

Spring Cloud Bus 是用轻量的消息中间件将分布式的节点连接起来,可以用于广播配置文件的更改或者服务的监控管理。关键的思想就是,消息总线可以为微服务做监控,也可以实现应用程序之间相通信。
Spring Cloud Bus 可选的消息中间件包括 RabbitMQ 和 Kafka 。
### 二、RabbitMQ 回顾
message queue
异步、解耦、削峰填谷


RabbitMQ 提供了 6 种工作模式:简单模式、work queues、Publish/Subscribe 发布与订阅模式、Routing
路由模式、Topics 主题模式、RPC 远程调用模式(远程调用,不太算 MQ;暂不作介绍)。

### 三、Bus 快速入门-运维

1、分别在 config-server 和 config-client中引入 bus依赖:bus-amqp
```
org.springframework.cloud
spring-cloud-starter-bus-amqp
org.springframework.boot
spring-boot-starter-actuator
```
1
2
3
4
5
6
7
8
9
2、分别在 config-server 和 config-client中配置 RabbitMQ
server 的配置文件:
```
server:
port: 9527
spring:
application:
name: config-server
# spring cloud config
cloud:
config:
server:
# git 的 远程仓库地址
git:
uri: https://gitee.com/ydlclass_cch/ydlclass-configs.git
label: master # 分支配置
#配置rabbitmq信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# 将自己注册到eureka中
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
# 暴露bus的刷新端点
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
client的配置文件 bootstrap.yml
```
# 配置config-server地址
# 配置获得配置文件的名称等信息
spring:
cloud:
config:
# 配置config-server地址
# uri: http://localhost:9527
# 配置获得配置文件的名称等信息
name: config # 文件名
profile: dev # profile指定, config-dev.yml
label: master # 分支
# 从注册中心去寻找config-server地址
discovery:
enabled: true
service-id: CONFIG-SERVER
#配置rabbitmq信息
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
management:
endpoints:
web:
exposure:
include: '*'
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1. 在config-server中设置暴露监控断点:bus-refresh
```
# 暴露bus的刷新端点
management:
endpoints:
web:
exposure:
include: 'bus-refresh'
```
1
2
3
4
5
6
bus自动在mq中建立交换机

只要微服务起起来,自动在mq中,建立队列,和交换机绑定

启动测试
1.git配置改变

2.往配置中心发请求
curl -X POST http://localhost:9527/actuator/bus-refresh

3.微服务自动重启

4.访问微服务,发现配置已经改变

## 第十五章 SpringCloud Stream消息驱动
### 一、Stream 概述

1.Spring Cloud Stream 是一个构建消息驱动微服务应用的框架。
2.Stream 解决了开发人员**无感知**的使用消息中间件的问题,因为Stream对消息中间件的进一步封装,可以做到代码层面对中间件的无感知,甚至于**动态的切换中间件**,使得微服务开发的高度解耦,服务可以关注更多自己的业务流程。
3.Spring Cloud Stream目前支持两种消息中间件RabbitMQ和Kafka
就像jdbc一样

**Stream 组件**

Spring Cloud Stream 构建的应用程序与消息中间件之间是通过绑定器 Binder 相关联的。绑定器对于应用程序而言起到了隔离作用, 它使得不同消息中间件的实现细节对应用程序来说是透明的。
binding 是我们通过配置把应用和spring cloud stream 的 binder 绑定在一起
output:发送消息 Channel,内置 Source接口
input:接收消息 Channel,内置 Sink接口
### 二、Stream 消息生产者
pom
```
stream-parent
com.ydlclass
1.0-SNAPSHOT
4.0.0
stream-producer
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-stream-rabbit
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
ProducerApp
```
package com.ydlclass.stream;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProducerApp {
public static void main(String[] args) {
SpringApplication.run(ProducerApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
application.yml
```
server:
port: 8000
spring:
cloud:
stream:
# 定义绑定器,绑定到哪个消息中间件上
binders:
ydlclass_binder: # 自定义的绑定器名称
type: rabbit # 绑定器类型
environment: # 指定mq的环境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
output: # channel名称
binder: ydlclass_binder #指定使用哪一个binder
destination: ydlclass_exchange # 消息目的地
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
消息发送类 MessageProducer
```
package com.ydlclass.stream.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Component;
import java.nio.charset.StandardCharsets;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@Component
@EnableBinding(Source.class)//这个类是stream的发送者
public class MessageProducer {
@Autowired
MessageChannel output;
public void send(String msg){
output.send(MessageBuilder.withPayload(msg).build());
System.out.println("MessageProducer 确实发了消息了!");
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
调用的controller ProducerController
```
package com.ydlclass.stream.controller;
import com.ydlclass.stream.producer.MessageProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @Created by IT李老师
* 公主号 “元动力课堂”
* 个人微 itlils
*/
@RestController
@RequestMapping("test")
public class ProducerController {
@Autowired
MessageProducer messageProducer;
//业务逻辑
@GetMapping("/send")
public String send(){
//发消息
String msg="使用stream来发消息了!";
messageProducer.send(msg);
return "success!";
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

### 三、Stream 消息消费者
pom
```
stream-parent
com.ydlclass
1.0-SNAPSHOT
4.0.0
stream-consumer
org.springframework.boot
spring-boot-starter-web
org.springframework.cloud
spring-cloud-starter-stream-rabbit
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
ConsumerApp
```
package com.ydlclass.stream;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
application.yml
```
server:
port: 9000
spring:
cloud:
stream:
# 定义绑定器,绑定到哪个消息中间件上
binders:
ydlclass_binder: # 自定义的绑定器名称
type: rabbit # 绑定器类型
environment: # 指定mq的环境
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
bindings:
input: # channel名称
binder: ydlclass_binder #指定使用哪一个binder
destination: ydlclass_exchange # 消息目的地
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
消息接收类 MessageListener
```
package com.ydlclass.stream.consumer;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Component;
/**
* 消息接收类
*/
@EnableBinding({Sink.class})
@Component
public class MessageListener {
@StreamListener(Sink.INPUT)
public void receive(Message message){
System.out.println(message);
System.out.println(message.getPayload());
}
}
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
测试

## 第十六章 SpringCloud Sleuth分布式请求链路追踪
### 一、概述

Spring Cloud Sleuth 其实是一个工具,它在整个分布式系统中能跟踪一个用户请求的过程,捕获这些跟踪数据,就能构建微服务的整个调用链的视图,这是调试和监控微服务的关键工具。
Zipkin 是 Twitter 的一个开源项目,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。
### 二、快速入门
1. 安装启动zipkin。 java –jar zipkin.jar

2. 访问zipkin web界面。 http://localhost:9411/

3. 在服务提供方和消费方分别引入 sleuth 和 zipkin 依赖
```
org.springframework.cloud
spring-cloud-starter-zipkin
```
1
2
3
4
5
6
7
8
9
10
4. 分别配置服务提供方和消费方。
provider
```
server:
port: 8001
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-provider
zipkin:
base-url: http://localhost:9411/ # 设置zipkin的服务端路径
sleuth:
sampler:
probability: 1 # 采集率 默认 0.1 百分之十。
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
consumer
```
server:
port: 9000
eureka:
instance:
hostname: localhost # 主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
zipkin:
base-url: http://localhost:9411/ # 设置zipkin的服务端路径
sleuth:
sampler:
probability: 1 # 采集率 默认 0.1 百分之十。
logging:
level:
com.ydlclass: debug
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
5. 启动,测试

调用关系图也能展现
