Spring Cloud Gateway

关于

什么是Spring Cloud Gateway?

This project provides a library for building an API Gateway on top of Spring WebFlux. Spring Cloud 
Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to 
them such as: security, monitoring/metrics, and resiliency.

翻译:

  • Spring Cloud Gateway是基于Spring WebFlux构建的API 网关。
    什么是 Spring WebFlux? : 从功能和使用上来讲,可以理解为类似SpringMvc,但是比SpringMvc更高级,更先进;从更新迭代上来讲,可以理解为是SpringMvc的替代品。
  • Spring Cloud Gateway提供了一种简单且有效的路由方式
  • Spring Cloud Gateway也提供了一些切面关注点,例如:安全,监控/指标和弹性(限流)。

Spring Cloud Gateway 特性

也可以理解为Spring Cloud Gateway 大致包含的内容有哪些。

  1. Built on Spring Framework 5, Project Reactor and Spring Boot 2.0

  2. Able to match routes on any request attribute.

  3. Predicates and filters are specific to routes.

  4. Circuit Breaker integration.

  5. Spring Cloud DiscoveryClient integration

  6. Easy to write Predicates and Filters

  7. Request Rate Limiting

  8. Path Rewriting

1. 基于Spring Framework 5, Project Reactor以及Spring Boot 2.0构建

Project Reactor是什么?

Reactor is a fourth-generation reactive library, based on the Reactive Streams
specification, for building non-blocking applications on the JVM

Reactor是一个第四代响应式编程类库,它是基于响应式流规范的,用于在JVM上构建非阻塞应用。

参考:
1. https://projectreactor.io/
2. https://spring.io/reactive

Reactor和Spring的关系

先看看Reactor响应式编程类库有什么特性(优势)?
Reactor响应式系统非常适合低延迟、高吞吐量场景的工作负荷
既然Reactor有如此优势,那Spring肯定想纳入己用,于是Spring5推出了自己的响应式编程库Reactive 。参见:Spring官网
在这里插入图片描述
附:

  • Project Reactor是一个运行在JVM上的反应式编程基础库,以“背压”的形式管理数据处理,提供了可组合的异步序列APIFlux和Mono。同时,它也实现了Reactive Streams 规范。
  • Project Reactor主要是由Pivotal公司开发和维护的,Spring框架也是该公司在维护,而且Spring Framework 5中默认使用Reactor作为反应式编程的实现由此虽然Reactor不是Spring的子项目,也有人称Reactor为Spring Reactor

关于Spring 的Reactive

参考:https://spring.io/reactive
在这里插入图片描述

  • Reactor
Reactive systems have certain characteristics that make them ideal for low-latency, high-throughput 
workloads. Project Reactor and the Spring portfolio work together to enable developers to build enterprise-
grade reactive systems that are responsive, resilient, elastic, and message-driven.

响应式系统具有某种特性,这些特性使得响应式系统非常适合低延迟、高吞吐量的场景。Project Reactor和Spring portfolio(Spring集)一起工作,使得开发者能够构建响应式的、弹力和消息驱动的企业级响应式系统。

What is reactive processing? 什么是响应式处理?

Reactive processing is a paradigm that enables developers build non-blocking, asynchronous applications 
that can handle back-pressure (flow control).

响应式处理是一种范例,使开发人员能够构建非阻塞的异步应用程序,可以处理背压(流量控制).

Why use reactive processing? 为什么要使用响应式处理?

反应式系统更好地利用了现代处理器。此外,在响应式编程中包含背压可确保解耦组件之间更好的弹性。

  • Project Reactor
Project Reactor is a fully non-blocking foundation with back-pressure support included. It’s the foundation 
of the reactive stack in the Spring ecosystem and is featured in projects such as Spring WebFlux, Spring 
Data, and Spring Cloud Gateway.

Project Reactor是完全非阻塞的、它也包含了背压(流控制)支持。
Project Reactro是Spring生态系统中的响应式栈的基础,它在Spring WebFlux、Spring Data以及Spring Cloud Gateway项目中起着重要作用。

参考:Project Reactor官网

  • Reactive Microservices
One of the main reasons developers move from blocking to non-blocking code is efficiency. Reactive code 
does more work with fewer resources. Project Reactor and Spring WebFlux let developers take advantage 
of multi-core, next-generation processors—handling potentially massive numbers of concurrent 
connections. With reactive processing, you can satisfy more concurrent users with fewer microservice 
instances.

开发者从阻塞编码转向非阻塞编码的一个主要原因是:效率。
响应式编码(非阻塞)可以用更少的资源做更多的事情。
Project Reactor和SpringWebFlux允许开发者利用多核心、下一代处理器来处理潜在的海量的并发连接。
使用响应式处理,用更少的微服务实例就可以满足更多的并发用户。

  • Reactive Microservices With Spring Boot
The Spring portfolio provides two parallel stacks. One is based on a Servlet API with Spring MVC and
 Spring Data constructs. The other is a fully reactive stack that takes advantage of Spring WebFlux and 
 Spring Data’s reactive repositories. In both cases, Spring Security has you covered with native support for 
 both stacks.

Spring集提供了两个并行栈。
一个是:基于Servlet API,如 SpringMVC和Spring Data的构造。
另一个是:利用Spring WebFlux和SpringData的响应式仓库的完全响应式栈。

在这里插入图片描述
其他图示如下,来源:https://blog.csdn.net/a1036645146/article/details/106383883
在这里插入图片描述

  • Integration with common technologies
Accessing and processing data in a reactive way is important. MongoDB, Redis, and Cassandra all have 
native reactive support in Spring Data. Many relational databases (Postgres, Microsoft SQL Server, 
MySQL, H2, and Google Spanner) have reactive support via R2DBC. In the world of messaging, Spring 
Cloud Stream also supports reactive access to platforms like RabbitMQ and Kafka.

2. Able to match routes on any request attribute.

能够匹配任何请求属性的路由。(关于路由可参见下面的 3 . Predicates and filters are specific to routes)

如何引入Spring Cloud Gateway

参见官网:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-starter
在这里插入图片描述
引入依赖spring-cloud-starter-gateway即可。
两个注意:
1、因为Spring Cloud Gateway是构建在Spring Boot 2.x, Spring WebFlux,以及Project Reactor上的。这就会导致之前熟悉的同步类库(如:Spring Data和Spring Security)可能不适用了。
2、Spring Cloud Gateway 需要Spring Boot和Spring Webflux提供的Netty运行环境(jar/依赖包)。Spring Coud Gateway项目不能建成WAR包,也不能在传统的Servlet容器上运行。

示例

pom.xml :只引入了spring-cloud-starter-gateway

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.xl.projects</groupId>
		<artifactId>xl-springcloud-parent-pom</artifactId>
		<version>1.0.0</version>
	</parent>
	<artifactId>xl-spring-cloud-gateway-demo001</artifactId>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
	</dependencies>
</project>

进入到spring-cloud-starter-gateway中可发现其他需要的依赖,如:netty相关依赖、reactor相关依赖等等。
在这里插入图片描述

主启动类:

package com.xl.projects.springcloudgateway.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringCloudGatewayDemoApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringCloudGatewayDemoApplication.class, args);
	}
}

启动:
在这里插入图片描述

成功启动!注意:启动的是Netty,并非Tomcat!

application.yml

server:
   port: 8085
spring:
   application:
      name: gateway-demo001-service
   cloud:
      gateway:
        routes:
        -  id: 2023-3-7 09:09:23
           uri: http://localhost:8080
           predicates:
           -  Path=/loadb
           -  Method=GET,PUT
           -  Header=header-name-01, header-value-01
           -  Header=header-name-02, header-value-02
           filters:
           - AddRequestHeader=X-Request-red, blue
           - AddRequestParameter=red, blue          

如上配置:

  1. 将端口配置为8085;
  2. 配置4个断言:
  • 1个Path=/loadb :请求须为localhost:8085/loadb
  • 1个Method=GET,PUT :请求须为 GET或者PUT方式
  • 1个Header : 请求时须加上一个名字为header-name-01,值为header-value-01的header
  • 第2个Header: 请求时须加上一个名字为header-name-02,值为header-value-02的header
    请求同时满足以上4个断言时,就会路由到另一个微服务上去,访问地址为uri+Path(http://localhost8080/loadb)
  1. 配置2个过滤器:
  • 增加一个Header: 名称为X-Request-red,值为blue
  • 增加一个请求参数:名称为red, 值为blue

准备一个微服务端口为8080,以及地址为/loadb的接口。 8080微服务代码:

package com.xl.module001.controller;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	
	@RequestMapping("/loadb")
	public String testLoadBalance(HttpServletRequest request,String red) {
		// 获取参数
		Enumeration<String> params = request.getParameterNames();
		String param = params.nextElement();
		System.out.println("=================param="+param);
		// 获取请求的Header
		Enumeration<String> headers = request.getHeaderNames();
		while (headers.hasMoreElements()) {
			System.out.println("+++++++++++++++++header="+headers.nextElement());
		}
		return "module001_8080";
	}
	
	@GetMapping("/netty/loadb")
	public String test3() {
		return "this is 8080 netty interface...";
	}
	
	@GetMapping("/")
	public String test4() {
		return "this is 8080 root directory";
	}
	
}

在这里插入图片描述
启动8080服务
在这里插入图片描述
启动8085网关服务
在这里插入图片描述
postman访问8085服务: localhost:8085/loadb

  • 请求方式为 POST
    在这里插入图片描述
    因为断言中配置了请求方式只能是 GET或者PUT,所以,POST会失败(无法路由到localhost:8085/loadb)。

  • 不加Header
    在这里插入图片描述
    同理,断言加了两个Header,这里没有加Header,必然会失败。

  • 满足4个断言的情况下,测试
    在这里插入图片描述
    如上图,路由成功,并返回预期结果。

测试下过滤器:
在这里插入图片描述
在这里插入图片描述

如上图,通过在8085网关中配置Header及参数,成功的路由到了8080服务中去。

路由中uri格式为:ip + 端口或者其他等价形式:域名、lb:微服务名称

测试: 配置uri时,在端口后面加上其他的路径,如:
在这里插入图片描述

在这里插入图片描述
结果没影响!

Spring Cloud Gateway中配置负载均衡

  • 准备3个微服务并注册到Nacos中
  1. Spring Cloud Gateway 网关
  2. Springboot 微服务1
  3. Springboot微服务2
    Springboot 微服务

微服务1: 监听8080端口

application.properties

server.port=8080
spring.application.name=nacos-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true

spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

#开启热部署
spring.devtools.restart.enabled=true

编写测试接口 /netty

在这里插入图片描述

package com.xl.module001.controller;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
	
	@RequestMapping("/loadb")
	public String testLoadBalance(HttpServletRequest request,String red) {
		// 获取参数
		Enumeration<String> params = request.getParameterNames();
		String param = params.nextElement();
		System.out.println("=================param="+param);
		// 获取请求的Header
		Enumeration<String> headers = request.getHeaderNames();
		while (headers.hasMoreElements()) {
			System.out.println("+++++++++++++++++header="+headers.nextElement());
		}
		return "module001_8080";
	}
	
	@GetMapping("/netty")
	public String test3() {
		return "this is 8080 netty interface...";
	}
	
	@GetMapping("/")
	public String test4() {
		return "this is 8080 root directory";
	}
	
}

微服务2: 监听8081端口
application.properties

server.port=8081
spring.application.name=nacos-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true

spring.cloud.nacos.username=nacos
spring.cloud.nacos.password=nacos

#开启热部署
spring.devtools.restart.enabled=true
# endpoints
 management.endpoints.web.exposure.include=*

测试接口: /netty
在这里插入图片描述

package com.xl.projects.controller;

import java.util.Date;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * For Test!!!
 * @author xl
 *
 */
@RestController
public class TestProviderController {
	
	/**
	 * For Test!
	 * @param param
	 * @return
	 */
	@GetMapping("/provider/test")
	public String test(String param) {
		return new Date().getSeconds()+
				", this is provider return msg: current param="+param;
	}

	@GetMapping("/loadb")
	public String testLoadBalance() {
		// 本地修改第29行
		return "8081";
	}
	
	@GetMapping("/netty")
	public String test() {
		return "this is 8081 microService";
	}
	
    // 服务器修改第31行
}// 本地修改了第33行 2023年3月1日19:38:21

配置Spring Cloud Gateway 网关
添加nacos服务注册依赖:
在这里插入图片描述
配置 application.yml
在这里插入图片描述

server:
   port: 8085
spring:
   application:
      name: gateway-demo001-service
   cloud:
      nacos:
        dicsovery:
           server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
      gateway:
        discovery:
           locator:
              enable: true
        routes:
        -  id: 2023-3-7 09:09:23
           uri: http://localhost:8080
           predicates:
           -  Path=/loadb2222
           -  Method=GET,PUT
           -  Header=header-name-01, header-value-01
           -  Header=header-name-02, header-value-02
           filters:
           - AddRequestHeader=X-Request-red, blue
           - AddRequestParameter=red, blue
        -  id: 2023-3-8 08:59:22
           uri: lb://nacos-provider
           predicates:
           -  Path=/netty     

启动Nacos,以及3个微服务:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 测试:通过网关访问 /netty,验证是否请求分摊到了 8080和8081两个服务?
    在这里插入图片描述
    在这里插入图片描述
    测试结果:一会8080,一会8081,符合预期

Spring Cloud Gateway顶层工作原理

在这里插入图片描述

Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping 
determines that a request matches a route, it is sent to the Gateway Web Handler.
 This handler runs the request through a filter chain that is specific to the request. 
 The reason the filters are divided by the dotted line is that filters can run logic 
 both before and after the proxy request is sent. All “pre” filter logic is executed. 
 Then the proxy request is made. After the proxy request is made, the “post” filter 
 logic is run.
  • 客户端对Spring Cloud Gateway发起请求,Gateway Handler Mapping会对请求进行处理,如果满足所有的断言,那就匹配到对应的路由。
  • 路由匹配成功后,就会将请求交给Gateway Web Handler处理,而Gateway Web Handler会给该请求加上一系列的过滤器链,过滤器可加在 代理请求 的前面或者代理请求 的后面。

3. Predicates and filters are specific to routes.

Predicates (断言)和filters (过滤器)是路由的重要组成部分。
这也引出了Spring Cloud Gateway的三大术语:
在这里插入图片描述

Route:

The basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates, and a collection of filters. A route is matched if the aggregate predicate is true.
在这里插入图片描述

如果所有的断言都是true,那么这个路由将被匹配。
由上可知,一个路由的组成:

  • id :唯一标识
  • uri:格式为 http://ip:端口 或者 域名 或者 lb://服务名(负载均衡实现)
  • preddcates: 复数,可配置多个,通过 符号短横杠“-”来标识每一个。
  • filters:复数,可配置多个,通过 符号短横杠“-”来标识每一个。

Predicate:

This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This lets you match on anything from the HTTP request, such as headers or parameters.

这个是JAVA8的函数式断言。输入类型是Spring框架的 ServerWebExchange。它可以匹配HTTP 请求的任何属性,如 headers 、parameters等等。

官网上对应介绍部分:
在这里插入图片描述

Spring Cloud Gateway matches routes as part of the Spring WebFlux HandlerMapping infrastructure.
 Spring Cloud Gateway includes many built-in route predicate factories. All of these predicates match on different attributes of the HTTP request. 
 You can combine multiple route predicate factories with logical and statements.
  • Spring Cloud Gateway 匹配路由是Spring WebFlux HandlerMapping基础设施的一部分(一种体现)。
  • Spring Cloud Gateway包含很多内嵌的路由断言工厂。这些断言可以匹配HTTP请求的很多属性。

例子:见上面 2 中的 “示例”。

Filter:

These are instances of GatewayFilter that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.

  • 这些过滤器是通过指定工厂构建出来的GatewayFilter实例。
  • 可以通过这些过滤器在发送下游请求之前或者之后修改请求和响应。

官网对应介绍:
在这里插入图片描述
例子:见上面 2 中的 “示例”。

4 Circuit Breaker integration

Spring Cloud Gateway 整合熔断降级

为什么需要熔断降级

在分布式系统中,网关作为流量的入口,因此会有大量的请求进入网关,向其他服务发起调用,其他服务不可避免的会出现调用失败(超时、异常),失败时不能让请求堆积在网关上,需要快速失败并返回给客户端,想要实现这个要求,就必须在网关上做熔断、降级操作。

为什么在网关上请求失败需要快速返回给客户端?

因为当一个客户端请求发生故障的时候,这个请求会一直堆积在网关上,当然只有一个这种请求,网关肯定没有问题(如果一个请求就能造成整个系统瘫痪,那这个系统可以下架了),但是网关上堆积多了就会给网关乃至整个服务都造成巨大的压力,甚至整个服务宕掉。因此要对一些服务和页面进行有策略的降级,以此缓解服务器资源的的压力,以保证核心业务的正常运行,同时也保持了客户和大部分客户的得到正确的相应,所以需要网关上请求失败需要快速返回给客户端。

  • 场景
    网关服务A调用业务服务B时,发现服务B无法调通(比如,断电了等),这时网关服务A就应该直接返回(使用熔断的fallback机制)。

Spring Cloud专门用于处理熔断降级的网关过滤器工厂: CircuitBreaker的用法

官网介绍:

https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-cacherequestbody-gatewayfilter-factory
在这里插入图片描述

1 说明

The Spring Cloud CircuitBreaker GatewayFilter factory uses the Spring Cloud CircuitBreaker APIs to wrap Gateway routes in a circuit breaker. Spring Cloud CircuitBreaker supports multiple libraries that can be used with Spring Cloud Gateway. Spring Cloud supports Resilience4J out of the box.

Spring Cloud的熔断API将网关路由包裹成一个熔断器,这就是Spring Cloud CircuitBreaker 网关过滤器工厂的做法。
Spring Cloud CircuitBreaker支持多个可用于Spring Cloud Gateway的库,其中,Spring Cloud支持对Resilience4J的开箱即用。

那么Resilience4J是什么?

  • Resilience4j是一个轻量级、易于使用的容错库,其灵感来自Netflix Hystrix,但专为Java 8和函数式编程设计。
  • Resilience4j提供高阶函数(decorators)来增强任何功能接口、lambda表达式或方法引用,包括断路器、速率限制器、重试或舱壁。可以在任何函数接口、lambda表达式或方法引用上使用多个装饰器。
  • circuitbreaker组件实现了断路器功能,是基于内存的断路器,采用
    ConcurrentHashMap来实现。
  • There are two starters for the Resilience4J implementations, one for reactive applications and one for non-reactive applications.(有两个Resilience4J 的Spring Cloud Starter实现,一个是响应式的应用,一个是非响应式的应用)—摘自:https://cloud.spring.io/spring-cloud-circuitbreaker/reference/html/spring-cloud-circuitbreaker.html

org.springframework.cloud:spring-cloud-starter-circuitbreaker-resilience4j- non-reactive applications

org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j- reactive applications

下面马上就会用到这个org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j
所以,可得org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j是Resilience4J的一种实现

2 引入熔断器依赖,并简单测试

To enable the Spring Cloud CircuitBreaker filter, you need to place spring-cloud-starter-circuitbreaker-reactor-resilience4j on the classpath. The following example configures a Spring Cloud CircuitBreaker GatewayFilter:

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: https://example.org
        filters:
        - CircuitBreaker=myCircuitBreaker

要使用Spring Cloud 熔断过滤器,需要引入依赖:spring-cloud-starter-circuitbreaker-reactor-resilience4j ,然后在application.yml中添加上面的配置即可开始使用:

pom.xml
在这里插入图片描述

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.xl.projects</groupId>
		<artifactId>xl-springcloud-parent-pom</artifactId>
		<version>1.0.0</version>
	</parent>
	<artifactId>xl-spring-cloud-gateway-demo001</artifactId>

	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-gateway</artifactId>
		</dependency>
		<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-circuitbreaker-reactor-resilience4j</artifactId>
		</dependency>
	</dependencies>

</project>

application.yml
在这里插入图片描述

server:
   port: 8085
spring:
   application:
      name: gateway-demo001-service
   cloud:
      nacos:
        dicsovery:
           server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
      gateway:
        discovery:
           locator:
              enable: true
        routes:
        -  id: 2023-3-7 09:09:23
           uri: http://localhost:8080
           predicates:
           -  Path=/loadb2222
           -  Method=GET,PUT
           -  Header=header-name-01, header-value-01
           -  Header=header-name-02, header-value-02
           filters:
           - AddRequestHeader=X-Request-red, blue
           - AddRequestParameter=red, blue
        -  id: 2023-3-8 08:59:22
           uri: lb://nacos-provider
           predicates:
           -  Path=/netty
        -  id: 2023-3-8 13:27:23
           uri: http://localhost:8080
           predicates:
           - Method=GET
           filters:
           - name: CircuitBreaker #或者配置这样 - CircuitBreaker=myCircuitBreaker
             args:
               name: myCircuitBreaker
#               fallbackUri: forward:/fallback
                      

其中,- name: CircuitBreaker 配置中的熔断器名称一定不能错,必须是CircuitBreaker (大小写敏感!)

演示:

  • 根据yaml文件的配置, uri为http://localhost:8080,如果不启动8080服务那么,就会触发熔断器:以达到检验熔断器是否引入成功
  • 启动本网关服务8085,并发送一个GET请求:
    在这里插入图片描述
    在yml中注释掉熔断相关的配置,再次测试:
    在这里插入图片描述
    在这里插入图片描述
    以上说明,引入熔断器,产生了作用。
3 添加fallbackuri配置

The Spring Cloud CircuitBreaker filter can also accept an optional fallbackUri parameter. Currently, only forward: schemed URIs are supported. If the fallback is called, the request is forwarded to the controller matched by the URI. The following example configures such a fallback:

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingServiceEndpoint
        filters:
        - name: CircuitBreaker
          args:
            name: myCircuitBreaker
            fallbackUri: forward:/inCaseOfFailureUseThis
        - RewritePath=/consumingServiceEndpoint, /backingServiceEndpoint

目前fallbackUri中只支持使用forward:来跳转。
在这里插入图片描述
在本网关服务8085中添加一个fallback接口,同样服务8080不启动,以触发熔断机制:
在这里插入图片描述
测试,成功返回“ttt”,说明fallbackUri配置生效:
在这里插入图片描述

4 fallbackUri添加变量

CircuitBreaker also supports URI variables in the fallbackUri. This allows more complex routing options, like forwarding sections of the original host or url path using PathPattern expression.

In the example below the call consumingServiceEndpoint/users/1 will be redirected to inCaseOfFailureUseThis/users/1.

application.yml 配置如下

spring:
  cloud:
    gateway:
      routes:
      - id: circuitbreaker_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingServiceEndpoint/{*segments}
        filters:
        - name: CircuitBreaker
          args:
            name: myCircuitBreaker
            fallbackUri: forward:/inCaseOfFailureUseThis/{segments}

验证,未成功!!

5 fallbakcUri可以指向自己服务的一个地址,也可以指向外部服务(通过路由转发)

The primary scenario is to use the fallbackUri to define an internal controller or handler within the gateway application. However, you can also reroute the request to a controller or handler in an external application, as follows

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: ingredients
        uri: lb://ingredients
        predicates:
        - Path=//ingredients/**
        filters:
        - name: CircuitBreaker
          args:
            name: fetchIngredients
            fallbackUri: forward:/fallback
      - id: ingredients-fallback
        uri: http://localhost:9994
        predicates:
        - Path=/fallback

在这里插入图片描述

测试: localhost:8085/test
在这里插入图片描述
以上,符合预期。

5 Spring Cloud DiscoveryClient integration

整合Spring Cloud 服务注册和发现

参见:2 《Able to match routes on any request attribute.》之 Spring Cloud Gateway中配置负载均衡

6 Easy to write Predicates and Filters

易于编写断言和过滤器
参见:以上内容有如何编写断言和过滤器,除此之外,官方还提供了以下了断言工厂和过滤器工厂:
参考:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/
在这里插入图片描述
在这里插入图片描述

7 Request Rate Limiting

  • TODO

8 Path Rewriting

The RewritePath GatewayFilter factory takes a path regexp parameter and a replacement parameter. This uses Java regular expressions for a flexible way to rewrite the request path. The following listing configures a RewritePath GatewayFilter:

spring:
  cloud:
    gateway:
      routes:
      - id: rewritepath_route
        uri: https://example.org
        predicates:
        - Path=/red/**
        filters:
        - RewritePath=/red/?(?<segment>.*), /$\{segment}

For a request path of /red/blue, this sets the path to /blue before making the downstream request. Note that the $ should be replaced with $\ because of the YAML specification.
示例:
在这里插入图片描述
在这里插入图片描述

以上都是使用yaml配置文件,也可以使用java代码完成配置

package com.xl.projects;

import java.time.Duration;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@SpringBootApplication
//@EnableDiscoveryClient
public class SpringCloudGateApplication {

	@RequestMapping("/circuitbreakerfallback")
	public String circuitbreakerfallback() {
		return "This is a fallback";
	}
	@Bean
	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
		//@formatter:off
		return builder.routes()
				.route("path_route", r -> r.path("/get")
//						.uri("http://httpbin.org"))
						.uri("http://localhost:8089"))
//				.route("host_route", r -> r.host("*.myhost.org")
				.route("host_route", r -> r.host("localhost:8085")
						.uri("http://127.0.0.1:8080"))
//						.uri("http://www.baidu.com"))
//						.uri("http://httpbin.org")) 
				.route("rewrite_route", r -> r.host("localhost:8087") // 不能加http://
						.filters(f -> f.rewritePath("/foo/(?<segment>.*)",
								"/${segment}"))
						.uri("http://localhost:8080")) // 必须要加上http://
//						.uri("http://httpbin.org"))
//						.uri("http://www.baidu.com"))
//						.filters(f -> f.rewritePath("/foo/(?<segment>.*)",
//								"/${segment}"))
//						.uri("http://httpbin.org"))
				.route("circuitbreaker_route", r -> r.host("localhost:8086")
						.filters(f -> f.circuitBreaker(c -> c.setName("slowcmd")))
								.uri("http://localhost:8079"))
				.route("circuitbreaker_fallback_route", r -> r.host("localhost:8074")
						.filters(f -> f.circuitBreaker(c -> c.setName("slowcmd").setFallbackUri("forward:/fallback")))
								.uri("http://localhost:8079"))
				.route("limit_route", r -> r.host("localhost:8088").and().path("/anything/**")
						.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
					.uri("http://httpbin.org"))
				.route("websocket_route", r -> r.path("/echo")
					.uri("ws://localhost:9000"))
				.build();
		//@formatter:on
		
	}
	@Bean
	RedisRateLimiter redisRateLimiter() {
		return new RedisRateLimiter(1, 2);
	}
	
	@Bean
	SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
		return http.httpBasic().and()
				.csrf().disable()
				.authorizeExchange()
				.pathMatchers("/anything/**").authenticated()
				.anyExchange().permitAll()
				.and()
				.build();
	}

	@Bean
	public MapReactiveUserDetailsService reactiveUserDetailsService() {
		UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
		return new MapReactiveUserDetailsService(user);
	}

	public static void main(String[] args) {
		SpringApplication.run(SpringCloudGateApplication.class, args);
	}
	
}

参考:

参考:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值