文章目录
一、SpringCloudGateway服务网关概论
1、SpringCloudGateway服务网关概论
Spring Cloud Gateway 用"Netty + Webflux"实现,不需要导入Web依赖。
- Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。
即Webflux中的Loop线程不仅可以处理请求和响应请求,还可以对业务中不阻塞的操作进行处理,从而提高它的利用率。阻塞的操作由work线程进行处理。 - Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。
Netty 是一个基于NIO的客户、服务器端的编程框架。提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 - Spring Cloud Gateway特点
1)易于编写谓词( Predicates )和过滤器( Filters ) 。其Predicates和Filters
可作用于特定路由。
2)支持路径重写。
3)支持动态路由。
4)集成了Spring Cloud DiscoveryClient。
2、SpringCloudGateway的三大核心概念
- 路由(Route)
这是网关的基本构建块。它由一个ID,一个目标URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
即根据URL请求去匹配路由。 - 断言(predicate)
输入类型是一个ServerWebExchange。我们可以使用它来匹配来自HTTP请求的任何内容,例如headers或参数。匹配请求内容。
匹配完路由后,每个路由上面都会有断言,然后根据断言来判断是否可以进行路由。 - 过滤(filter)
在匹配完路由和断言为真后,可以在请求被路由前或者之后对请求进行修改。
即根据业务对其进行监控,限流,日志输出等等。
二、SpringCloudGateway的路由及断言
1、子模块项目SpringCloudGateway的搭建
-
在cloud父项目中新建一个模块Module,创建子模块网关cloud-gateway-gateway9527
-
在POM文件中添加如下依赖
<?xml version="1.0" encoding="UTF-8"?> <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"> <parent> <artifactId>cloud</artifactId> <groupId>com.zzx</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-gateway-gateway9527</artifactId> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <!-- 引入网关Gateway依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.22</version> </dependency> <!-- 引入Eureka client依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- actuator监控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies> </project>
-
在gateway子模块中创建包com.zzx,在包下创建主启动类GatewayMain9527
package com.zzx; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @Slf4j public class GatewayMain9527 { public static void main(String[] args) { SpringApplication.run(GatewayMain9527.class,args); log.info("************ GatewayMain9527服务 启动成功 *************"); } }
-
在resources目录下创建application.yml文件,配置如下
server: port: 9527 spring: cloud: gateway: routes: # 路由ID,没有固定规则但要求唯一,建议配合服务名 - id: cloud-payment-provider # 匹配后提供服务的路由地址 (即目标服务地址) uri: http://localhost:8001 # 断言会接收一个输入参数,返回一个布尔值结果 predicates: # 路径相匹配的进行路由 - Path=/payment/*
-
测试
1)先开启7001和7002的Eureka服务,payment8001服务提供者和gateway9527服务。
2)在浏览器使用9527端口,也就是网关进行访问payment8001服务即可。
在浏览器输入:http://localhost:9527/payment/index
2、SpringCloudGateway_Java API构建路由
-
在子模块cloud-gateway-gateway9527中的com.zzx包下,创建包config,并在包下创建GatewayConfig
package com.zzx.config; import org.springframework.cloud.gateway.route.RouteLocator; import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class GatewayConfig { @Bean public RouteLocator routeLocator(RouteLocatorBuilder builder){ //获取路由 RouteLocatorBuilder.Builder routes = builder.routes(); /** * 设置路由 * 1.路由id * 2.路由匹配规则 * 3.目标地址 */ routes.route("path_route",r->r.path("/payment/*").uri("http://localhost:8001/")).build(); return routes.build(); } }
-
测试
1)将yml文件中的gateway配置注释掉,然后重启该服务。
2)在浏览器上访问:http://localhost:9527/payment/index
3、SpringCloudGateway的动态路由功能
-
再添加一个服务提供者,用以实现Gateway网关的动态路由的功能。
1)复制payment8001服务,然后点击cloud父工程,ctrl+v进行粘贴,修改名字为8002
2)修改POM文件:<artifactId>cloud-provider-payment8002</artifactId>
3)将POM右键,选择添加为Maven项目Add as Maven Project
4)修改com.zzx包下的启动类的名字以及类中的名字package com.zzx; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * 主启动类 */ @SpringBootApplication @Slf4j public class PaymentMain8002 { public static void main(String[] args) { SpringApplication.run(PaymentMain8002.class,args); log.info("****** PaymentMain8002服务启动成功 *****"); } }
5)将yml文件的端口号port和instance-id的名字有8001部分都修改为8002
然后在启动类中运行该payment8002服务。 -
修改gateway9527项目的yml文件
server: port: 9527 eureka: instance: # 注册名 instance-id: cloud-gateway-gateway9527 client: service-url: # Eureka server的地址 #集群 defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka #单机 #defaultZone: http://localhost:7001/eureka/ spring: application: #设置应用名 name: cloud-gateway cloud: gateway: routes: # 路由ID,没有固定规则但要求唯一,建议配合服务名 - id: cloud-payment-provider # 匹配后提供服务的路由地址 (即目标服务地址) lb后跟提供服务的微服务的名字 uri: lb://CLOUD-PAYMENT-PROVIDER # 断言会接收一个输入参数,返回一个布尔值结果 predicates: # 路径相匹配的进行路由 - Path=/payment/*
-
注释之前的配置文件GatewayConfig中的方法。
-
在服务提供者payment8001和payment8002中的com.zzx.controller的PaymentController类中添加如下代码
@Value("${server.port}") private String port; @GetMapping("lb") public String lb(){ return port; }
即通过该lb的url请求来测试动态路由是否配置生效。
-
测试动态路由是否配置生效。
1)重启payment8001和payment8002以及gateway9527服务
2)浏览器中访问:http://localhost:9527/payment/lb
此时刷新后随即出现8001或8002,估计是轮询的策略。
4、SpringCloudGateway的路由断言
-
UTC时间格式的时间参数时间生成方法
package demo; import java.time.ZonedDateTime; public class Test1 { public static void main(String[] args) { ZonedDateTime now = ZonedDateTime.