Spring Cloud
关于集群、分布式、微服务
集群,将同一份任务分到多个服务器上,每个服务器都是一个节点,每个节点目的是处理一个共同的任务,主要注重解决服务压力问题
分布式,将一个大的业务,分成多个小的功能,比如一个 OJ 系统,就可以分为网关、判题服务、用户服务、博客服务等。
微服务,和分布式思想上有些类似,但是分布式更多倾向于分了就行,微服务是将功能差分到更小更细(通常拆分到不能再拆分)
优点:
易于开发、维护:一个团队只需要专心实现一个功能,不需要考虑全局功能实现
**技术栈选型方便:**各个微服务之间设置可以选择不同的语言(本身各个微服务之间通过 REST、RPC 等进行通信,这是和语言无关的),需要性能的可以使用 C++,其他需要快速开发的可以直接使用 Java、Go 等
扩展性好,容错性好
缺点:
运维难度高:单机架构只需要监控一台机器的资源,但是微服务既需要监控整个链路,有需要监控单个服务
服务间依赖关系:一个服务改动,如果动了接口,可能会涉及到其他很多服务改变
网络通信成本:波动的网络环境等因素会影响服务间的信息传递,测试开发需要增加这些因素考虑
负载均衡:多个节点之间的选择,需要设计合适的负载均衡策略、服务发现策略
微服务的拆分思想
单一原则:一个微服务负责完成一个功能,如果仍然能够基于功能区分,则不满足单一原则
服务自治:从开发、测试、部署、运行,一个微服务都能够独立完成
不能存在循环依赖:例如 A -> B,B -> C,C -> A,就是典型的循环依赖
一、REST
REST,指的是 Re presentational S tate Transfer,表现层资源状态转移,其中涉及下面三个概念
-
表现层 ,资源的表现形式,比如文本可以通过 txt、HTML、JSON 等形式甚至二进制的方式表现
-
资源 ,网络上的一切都可以抽象为资源,对应唯一资源标识符(URI)
-
状态转移 ,访问 URI,使用 HTTP 进行资源操作,对资源的增删查改都涉及到资源的状态转移
RESTful API 是指借鉴 REST 风格的接口设计,主要涉及两个概念
-
资源 ,可以是音频、图片、视频、文本等。除二进制数据外,其他更多通过 JSON 的方式传递,通常从数据库中取到
-
统一接口 ,RESTful 的接口,对于资源的具体操作只能从 HTTP 请求方法中看出,请求中只含有资源的种类,简单来说:接口只有名词,动词(即资源操作)体现在请求方法
REST 方法对于请求方法的要求较高,但是有的浏览器对于除 GET、POST 之外的请求方法支持不好;请求方法不在请求中直接体现,需要通过抓包的方式查看。所以依据情况选择设计风格
RestTemplate 是 Spring 提供的同步 HTTP 客户端,一般通过它调用 RESTful 的接口,如果只是需要简单进行微服务间的调用、申请其他服务资源等,可以使用。附带 RestTemplate 使用博客:
https://www.cnblogs.com/54chensongxia/p/11414923.html
二、服务注册与发现
2.1 CAP 理论
一个分布式系统,存在下面的关系图

-
P ,Partition Tolerance,分区容错性。这里的分区指的是网络分区,指的是分布式系统中各个节点沟通不畅的情况(是节点间的网络发生问题,而不是节点本身挂掉)
-
C ,Consistency,一致性,各个节点之间持有的数据是相同的
-
A ,Availability,可用性,不管何时对集群请求,总是能得到结果(正确性不保证)
根据 CAP 理论,C、A、P 是不可全部实现的
在实际操作中,网络波动是不可避免地,所以会选择实现分区容错性,那么接下来有两种架构方向:AP、CP
AP 即保证可用性,在出现网络分区时,为了保证数据可用性,仍然返回节点当前持有的数据(这意味着数据可能是错误的,或者说不是最新的),后续通过异步同步数据,最后实现数据的统一性(即 AP 架构放弃了强一致性,最终还是会实现数据一致的)
CP 即保证一致性,在发生网络分区时,选择不返回数据,等到网络分区结束并且数据同步后,再进行请求处理、数据返回
2.2 常见的注册中心
-
Eureka,AP。现在除非维护老项目不建议使用了,因为已经进入只读状态,除了严重bug不再更新,但依然是 SpringCloud 服务发现与注册的默认实现
-
Zookeeper,CP,国内 Java 体系常用于作为服务注册中心
-
Nacos,AP/CP,默认 AP,功能更多,包括服务发现、服务注册、配置中心等
2.3 Eureka
Eureka 作为一个微服务运行,分为两大部分 Eureka Server、Eureka Client。Eureka Server 对实例进行健康监测并提供服务注册,Eureka Client 将微服务的 IP、端口、服务信息提供到 Eureka Server
2.3.1 Eureka Server
-
导入依赖
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> -
在微服务 SpringBoot 入口启动服务注册
java@EnableEurekaServer //开启 Eureka 服务注册 @SpringBootApplication public class EurekaServiceApplication { public static void main(String[] args){ SpringApplication.run(EurekaServiceApplication.class, args); } -
配置 Eureka 服务注册地址
yamleureka: instance: hostname: localhost client: fetch-registry: false register-with-eureka: false service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
其中,eureka 几项配置为:
-
fetch-registry,是否从其他 Eureka 节点获取注册信息,默认是 true,如果是单点 Eureka 的话,设置为 false -
register-with-eureka,是否将当前服务注册到 Eureka,默认是 true。对于一个 Eureka Server 本身来说,不需要进行注册,设置为 false -
defaultZone,设置服务注册地址,后续注册服务、获取服务列表都需要使用这个 URL
打开 Web 界面,可以查看 Eureka Server 中的服务注册信息

其中,红色的表示是因为当前每分钟 Eureka 收到的心跳总数远低于预期,Eureka 不再剔除节点,即使没有收到心跳包。当服务节点过少时必然发生,可忽略,计算公式:
最后一分钟收到的心跳数 < 期望心跳数 * 85%,满足则进入 "自我保护模式",也就是如上图所示。这是 Eureka AP 思路的典型体现之一
2.3.2 Eureka Client
-
导入依赖
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> -
配置服务注册地址,注册自身服务,当服务启动时,自动向 Eureka Server 注册
yamleureka: client: service-url: defaultZone: http://127.0.0.1:10010/eureka -
RestTemplate 开启负载均衡能力
java@Configuration public class BeanConfig { @Bean @LoadBalanced // 通过 Spring Cloud Load Balancer 实现负载均衡 public RestTemplate getRestTemplate(){ return new RestTemplate(); } } -
从服务中心获取服务
javaList<ServiceInstance> servers = discoveryClient.getInstances("product-service"); //获取服务实例列表 EurekaServiceInstance server = (EurekaServiceInstance)servers.get(0); //去列表中取第一个 String url = server.getUri() + "/product/" + orderInfo.getProductId(); //根据实例信息拼接请求 String ret = restTemplate.getForObject(url, String.class);
2.4 负载均衡
观察上面的代码,获取实例列表后只是粗暴地取了一个实例,这样容易每次都选到同一个节点进行请求,也就失去了微服务多节点的意义,所以要 "负载均衡" 的选择实例
Spring Cloud LoadBalancer 是 Spring Cloud 内置的负载均衡器,默认通过轮询的方式实现负载均衡(也可以改为随机的方式)
使用
给 RestTemplate 的配置加上 @LoadBalanced 注解,使用 RestTemplate 发送请求时,通过 service-name 代替 ip:port 的方式配置请求即可自动完成负载均衡的服务调用
java
@Component
public class BeanConfig {
@Bean
@LoadBalanced // 通过 Spring Cloud Load Balancer 实现负载均衡
RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
这里
service-name,来源于微服务配置中的spring.application.name,和 Nacos 使用是一样的。
请求构造
java
String url = "http://product-service/product/" + orderInfo.getProductId();
Spring Cloud LoadBalancer 是通过 LoadBalanceInterceptor 拦截实现的,向服务注册中心获取服务并将服务名替换为 ip:port 的形式
需要注意的是,负载均衡的引入不能重复,不可以既导入 Enreka,又导入 Nacos
Spring Cloud LoadBalancer 实现原理:通过拦截器对 RestTemplate 的请求进行拦截,获得请求中的
service-name,到 Eureka 获取服务列表,再将ip:port拼接回字符串,继续进行请求
2.5 Nacos(Dynamic Naming and Configuration Service)
主要用于进行服务注册、服务发现、配置中心、流量管理,和 SpringCloud Gateway 结合,Nacos 提供实例列表,由 SpringCloud Gateway 进行负载均衡的选择
2.5.1 Docker 部署
shell
sudo docker run -d --name nacos -p 8848:8848 -p 9848:9848 -e MODE=standalone nacos/nacos-server:v2.3.2
使用 docker 部署后,进入容器可以看到 Nacos 的运行目录,如果出现问题时往往需要在这里进行处理
shell
diinkikot@DESKTOP-EI61K7J:~/nacos/bin$ sudo docker exec -it nacos /bin/bash
[root@79168aedf03c nacos]# ls
LICENSE NOTICE bin conf data derby.log logs start.out target work
或者也可以在 Linux 通过 zip 压缩包解压后运行,目录如下
shell
diinkikot@DESKTOP-EI61K7J:~/nacos$ ls
LICENSE LICENSE:Zone.Identifier NOTICE NOTICE:Zone.Identifier bin conf data logs target
其中,bin 中包含了 nacos 启动、停止脚本,conf 中包含配置文件(如配置端口,默认为 8848,对应需同时保证 9848、9849 未被占用,即需同时开放 Nacos 端口号 + 1000 和 Nacos 端口号 + 1001 ;data 中为服务数据)
2.5.2 快速上手
-
在父工程的
dependencyManagement中导入 Spring Cloud Alibaba 依赖,打包方式为 pom 统一管理版本xml<spring-cloud-alibaba.version>2022.0.0.0-RC1</spring-cloud-alibaba.version> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> -
关于 SpringBoot、Spring Cloud、Spring Cloud Alibaba 的版本问题
https://sca.aliyun.com/zh-cn/docs/2022.0.0.0/overview/version-explain/
-
导入 Nacos 依赖与 Load Balance
xml<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-loadbalancer</artifactId> </dependency> -
配置 Nacos 地址,配置项
spring.cloud.nacos.discovery.server-addryaml# application.yaml spring: cloud: nacos: discovery: server-addr: localhost:8848 -
进行远程调用:与 Eureka 不同,Nacos 不用通过微服务的方式运行,而是和 MySQL、Redis 一样单独运行;并且负载均衡的调用和 Eureka 的相同,因为都是通过 Spring Cloud LoadBalancer 实现负载均衡器 - 请求的转接
-
RestTemplate 开启负载均衡能力
java@Configuration public class BeanConfig { @Bean @LoadBalanced // 通过 Spring Cloud Load Balancer 实现负载均衡 public RestTemplate getRestTemplate(){ return new RestTemplate(); } }
-
-
从服务中心获取服务,或者用
service-name代替ip:port的方式自动选择实例路由java//从服务中心获取服务 List<ServiceInstance> servers = discoveryClient.getInstances("product-service"); //获取服务实例列表 EurekaServiceInstance server = (EurekaServiceInstance)servers.get(0); //去列表中取第一个 String url = server.getUri() + "/product/" + orderInfo.getProductId(); //根据实例信息拼接请求,后续可以通过 RestTemplate 发起调用 //自动路由 String uri = "http://cloud-product/product/get_product_name?id=1"; System.out.println(restTemplate.getForObject(uri,String.class));
2.5.3 Nacos 负载均衡
Spring Cloud LoadBalancer 有自己的负载均衡实现方式,所以需要额外的配置让 Nacos 的权重配置、同集群优先访问生效。
在负载均衡的过程中,Nacos 负责提供实例列表,由 Spring Cloud LoadBalancer(Spring Cloud 集成) 进行负载均衡的实例选择。因此,下面的配置应该写在需要有权重选择实例的服务中
yamlspring: cloud: loadbalancer: nacos: enabled: true
-
Nacos 网页管理页面中可以下线服务、配置权重。
-
Nacos 会把同一个机房中的机器上的服务认为在同一个集群上,这样这些节点之间的访问是要快于跨局域网的,即某种程度上可以是认为是同一机房优先访问
配置集群名称,通过
spring.cloud.discovery.cluster-nameyamlspring: cloud: discovery: cluster-name: SH
Nacos 同集群优先访问和权重配置
优先根据同集群优先访问,获得同集群的实例列表
剔除不健康的实例
在同集群的实例中,根据权重配置,分配节点
如果同集群中没有可访问实例,则跨集群兜底,根据权重配置访问节点
总结:同集群优先访问 > 权重配置
服务发现策略
Nacos 基于 "推" 模式,当实例列表发生更改时,会主动推送给订阅者;而 Eureka 基于 "拉" 模式,30s 拉取一次,订阅者进行缓存
2.5.4 Nacos 健康检查
2.5.4.1 健康检查机制
-
客户端主动上报,即客户端主动发送信息表明尚未下线,默认间隔 5s 发送,30s 内无响应咋认为节点下线删除节点
-
服务端反向探测,服务端发送信息主动确认客户端的情况,20s 没有反应会将节点标记为 unhealthy,而不会下线节点
2.5.4.2 临时实例和非临时实例
Nacos 对于临时实例使用客户端主动上报,宕机进行删除;而持久化实例使用的是服务端反向探测,即使宕机也不会删除。节点默认是临时实例,如果需要设置为非临时实例,需要如下配置
yaml
spring:
cloud:
discovery:
ephemeral: false
报错:当前节点为临时实例不可转换为非临时实例,或者当前节点为非临时实例不可转换为临时实例
原因是 Nacos 会记录每个实例的 ip、端口,在两者都没有更改时是不允许转换的。
解决方式:
更改端口
以 docker 为例,进入容器后,删除
/data/protocol中的内容,之后重启容器,即可以完成转换实例状态正常,但是显示 unhealthy
对于非临时节点来说,Nacos 的健康检查方式是主动发送信息确认。但是对于通过阿里云内部 MSE 托管的 Nacos 来说,为了安全规范禁止服务端主动向客户端发送请求,所以误认为非临时实例下线
解决方式:将实例设置为非临时实例,参考文档
2.5.5 Nacos 服务环境隔离
常见的环境包括:
-
开发环境
-
测试环境
-
生产环境
不同环境,服务器规格、环境配置不同
通过 namespace 进行,配置为 spring.cloud.discovery.namespace;不同命名空间的服务不能互相访问(获取实例列表)
yaml
spring:
cloud:
discovery:
namespace: namespace-id # 在 nacos 中建立 namespace,并将命名空间 id 放在这里
2.5.6 Nacos 配置中心
2.5.6.1 Nacos 服务器建立配置文件
-
目前支持的方式有 yaml、properties(其他选项仅限于有)
-
Data-Id,对应到项目名称,比如 product-service、order-service
2.5.6.2 客户端服务器获取配置
-
客户端相应配置都要放在 bootstrap.* 中,文件类型需要和 Nacos 服务端配置文件的类型相同,默认需要指定的有项目名称和 Nacos 服务器地址。Nacos 的服务注册中心地址和配置中心地址是在两个不同的项中
yamlspring: application: name: product-service profiles: active: dev cloud: nacos: config: server-addr: localhost:8848 -
导入 Nacos Config 依赖
xml<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!-- SpringCloud 2020.*之后版本需要引入bootstrap--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> -
在启动微服务时,会首先通过 bootstrap.yaml 尝试从 Nacos 获取配置,之后和 application.yaml/.properties 的配置进行合并
关于 data-id
Nacos 的 data-id,完整格式为
${prefix}-${spring.profiles.active}.${file-extension}
prefix,默认为spring.application.name,也可以通过spring.cloud.nacos.config.prefix指定
spring.profiles.active,可以为空,此时-将被自动去除
file-extension,默认为properties,可以通过spring.cloud.nacos.config.file-extension服务启动时,会依次读取下面的配置
${prefix}-${spring.cloud.nacos.config.file-extension}.${file-extension}
${prefix}.${file-extension}
${prefix}
2.5.6.3 配置中心命名空间
配置中心的命名空间和服务发现的命名空间是两个不同的命令空间,但默认都是 public,同时也都可以起到隔离的作用
yaml
spring:
cloud:
nacos:
config:
namespace: 6e61929d-a9bd-4504-9031-6ca57bc6c0b0
2.5.6.4 共享配置
上面介绍的是 "单一服务 <-> 单一配置",但是很多配置,例如 MySQL、Redis、RabbitMQ 这些中间件的配置,往往是可以复用的,每份配置都放一次,过于冗余臃肿
Nacos 支持共享配置,放在 spring.cloud.nacos.config.shared-configs ,通过数组的方式指定要加载的配置的 data-id
例如下面
yaml
spring:
cloud:
nacos:
config:
shared-configs:
- data-id: share-mysql-dev.yaml
- data-id: share-redis-dev.yaml
- data-id: share-rabbitmq-dev.yaml
2.5.7 AP 与 CP
Nacos 既可以 AP 架构,也可以 CP 架构,对于临时节点采取 AP 的策略(宕机删除),对于非临时节点采取 CP 策略(对于持久化实例,即使宕机,也不删除)
三、远程调用
RPC(Remote Procedure Calling),是微服务间通信常用方式之一(另一个是 HTTP)。
Feign,最早由 Netflix 开发,后来 17 年停更后发展为 OpenFeign,Spring Cloud 深度集成。
3.1 快速上手
RPC ,Remote Process Calling,是指像调用本机方法一样调用远程的方法。在 Spring 中常使用 OpenFeign,将 REST 客户端转化为 Java 接口
一般规范,微服务间的 HTTP 通信接口遵循 RESTful 的设计,通过 GET、POST、DELETE 的方法完成资源的操作,数据格式一般是 Json。而发起调用的一方,就是客户端。例如上面我们通过
RestTemplate进行 HTTP 调用,就是一个 REST 客户端
-
在要进行远程调用的服务消费者,导入 OpenFeign 依赖(这里选择 openfeign,feign 已停止更新)
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> -
给启动类增加 @EnableFeignClients 注解,开启 OpenFeign 功能
java@EnableFeignClients @SpringBootApplication public class OrderServiceApplication { public static void main(String[] args){ SpringApplication.run(OrderServiceApplication.class, args); } } -
编写 OpenFeign 客户端,通过 SpringMVC 的方式指定请求路径、请求参数、服务名称(Spring 自行通过
value指定的服务名称通过LoadBalancer进行负载均衡,等价于使用 RestTemplate 时用service-name代替ip:port的做法),接口需要使用@FeignClient修饰java@FeignClient(path="/product", value="product-service") public interface ProductApi { @RequestMapping("/get_num") public Integer getNum(Integer num); @RequestMapping("/test1") public String test1(@RequestParam("num1") Integer num1, @RequestParam("num2") Integer num2); @RequestMapping("/test2") public String test2(ProductInfo productInfo); @RequestMapping("/{id}") public ProductInfo selectProductById(@PathVariable("id") Integer id); @RequestMapping("/test3") public String test3(@RequestBody ProductInfo productInfo); }
path 为所有请求的前缀路径,对应 @RequestMapping 作用于 Controller 类时的效果
-
远程调用,像调用本地方法一样
java@Autowired private ProductApi productApi; @RequestMapping("get_num") Integer getNum(Integer num){ log.info(num + ""); return productApi.getNum(num); }
3.2 参数传递
FeignClient 起到了一个代替我们手动拼接字符串发送请求的作用,所以说参数对应的关系依然是存在的,需要满足 Spring MVC 的参数传递规则,例如
-
单参数传递
java@RequestMapping("/get_num") public Integer getNum(Integer num) -
多参数,需要使用
@RequestParam绑定参数(默认 required = true)java@RequestMapping("/test1") public String test1(@RequestParam("num1") Integer num1, @RequestParam("num2") Integer num2); -
传递对象,如果目的是将对象作为请求字符串的一部分,需要加上
@SpringQueryMap注解,自动将类序列化后加入请求参数;否则默认将对象加入请求正文java@RequestMapping("/test2") public String test2(@SpringQueryMap ProductInfo productInfo); -
传递 JSON,放在请求正文中。在服务消费者接受请求,从正文中取数据,使用
@RequestBody;服务消费者调用 Feign 客户端,同样使用@RequestBody,不过这里的意思是告诉 FeignClient 进行远程调用的时候,将数据拼接到请求正文中。一个是取数据,一个是放数据java//ServiceConsumerController or ServiceProvidorController @RequestMapping("/test3") public String test3(@RequestBody ProductInfo productInfo){ //FeignClient @RequestMapping("/test3") public String test3(@RequestBody ProductInfo productInfo);
3.3 抽取式和继承式
按照上面的方式,我们要根据服务提供方的接口设计单独"描绘"出来一个 FeignClient 客户端,将 REST 客户端转化为 Java 接口;同时不同服务调用这个服务时,都需要重复一遍上述步骤,多出了很多代码。
所以我们选择把这些接口单独抽出来,放到一个 api 模块中,这个模块只放接口和 DTO,由服务提供者实现接口中的内容,这样就解决了一个问题:每个服务调用者都要"描绘"一遍服务提供者的 Controller
现在还有一个问题,每个服务调用者的 FeignClient 呢?有两种代码构建方式
继承式 是 OpenFeign 推荐的方式,将存放接口的模块单独打成 jar 包,放到本地仓库中,然后需要调用服务的模块引入,自己的 FeignClient(使用 @FeignClient 修饰的类)继承这个接口,这样就完成了 FeignClient 的编写

抽取式 使更多实际使用的方式,在 api 模块中定义接口时,将这个接口作为 FeignClient,使用 @FeignClient 注解修饰并由服务提供者实现,将这个模块打 jar 包后分发给服务调用者;服务调用者必须要再自己定义 FeignClient,只需要在自己的启动类处通过 @EnableFeignClients 的方式指定扫描路径或者客户端类即可。
这种方式服务消费者需要完成的工作更少,但是可能会导致依赖版本问题以及以来臃肿问题
java
@EnableFeignClients(basePackages = {"com.wjl.api"}) //指定扫描路径
@EnableFeignClients(clients = {ProductApi.class}) //指定要加载的 feign client 客户端
四、网关
前面介绍了服务注册与发现、负载均衡、远程调用,还缺少一个网关,作为整个后端服务的入口。
网关可以起到如下作用
-
对请求进行鉴权过滤
-
一切请求经过网关,起到动态路由的作用
-
流量限制,按照后端服务能接受的流量放行请求
网关我们介绍 Spring Cloud Gateway,和 Eureka 一样作为一个服务在后端运行
4.1 快速上手
-
导入依赖
xml<!--网关--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!--基于nacos实现服务发现依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--负载均衡--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency> -
添加路由配置
yamlserver: port: 10030 spring: application: name: gateway cloud: nacos: discovery: server-addr: localhost:8848 gateway: routes: - id: product-service uri: lb://product-service predicates: - Path=/product/** #filters: #- AddRequestParameter=username, wjl - id: order-service uri: lb://order-service predicates: - Path=/order/** # 路径匹配规则 - After=2025-01-01T00:00:00.000+08:00[Asia/Shanghai] # 时间限制规则-
server.port,网关的ip、端口 -
spring.cloud.gateway.routes,路由配置,后续通过 yaml 数组的语法添加多条路由配置-
id,路由id,保证唯一即可 -
uri,只能是普通 uri ;或者通过lb://service-name的方式,到注册中心获取实例列表,由 Spring LoadBalancer 负载均衡的调用(lb 代表负载均衡) -
predicates,路由条件,只有符合要求要求的请求会被路由到相应服务
-
-
4.2 Gateway Filter Factories
Predicates 决定了哪些请求需要被处理,而 filter 负责对请求处理前后增添额外的逻辑,包含两种
4.2.1 GatewayFilter
作用于一个或一组路由
yaml
spring:
cloud:
gateway:
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/product/**
filters:
- AddRequestParameter=username, wjl
GatewayFilter 提供了很多 Filter,AddRequestParameter 会在所有请求中加上参数,可以后端直接获取
这种方式作用于部分接口,可以通过 default-filters 作用于所有路由接口
yaml
spring:
cloud:
gateway:
default-filters:
- AddRequestParameter=username, wjl
routes:
- id: product-service
uri: lb://product-service
predicates:
- Path=/product/**
4.2.2 GlobalFilter
作用于所有路由
添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
添加配置
yaml
spring:
cloud:
gateway:
metrics:
enabled: true
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
shutdown:
enabled: true
4.2.3 执行顺序
-
通过
@Order指定优先级,越小,优先级越高 -
默认优先级为 0,优先级相同时,defaultFilter > GatewayFilter > GlobalFilter