Spring Cloud Gateway的动态路由实现

× 文章目录
  1. 1.前言
  2. 2. Spring Cloud Gateway简单的动态路由实现
  3. 3. 简单动态路由的实现
    1. 3.1 新建Maven工程ch18-7-gateway
    2. 3.2 根据Spring Cloud Gateway的路由模型定义数据传输模型
    3. 3.3 编写动态路由实现类
    4. 3.4 编写Rest接口
    5. 3.5 配置application.yml文件
    6. 3.6 启动ch18-7-gateway应用测试
  4. 4.Spring Cloud Gateway推荐文章
  5. 5.《重新定义Spring Cloud实战》中的Spring Cloud Gateway

摘要:本文主要介绍了Spring Cloud Gateway的动态路由的简单实现方式。

1.前言

网关中有两个重要的概念,那就是路由配置和路由规则,路由配置是指配置某请求路径路由到指定的目的地址。而路由规则是指匹配到路由配置之后,再根据路由规则进行转发处理。
Spring Cloud Gateway作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,尽量避免重启,需要实现Spring Cloud Gateway动态路由配置。前面章节介绍了Spring Cloud Gateway提供的两种方法去配置路由规则,但都是在Spring Cloud Gateway启动时候,就将路由配置和规则加载到内存里,无法做到不重启网关就可以动态的对应路由的配置和规则进行增加,修改和删除。本篇文章简单介绍如何实现Spring Cloud Gateway的动态路由。

2. Spring Cloud Gateway简单的动态路由实现

Spring Cloud Gateway的官方文档并没有讲如何动态配置,查看 Spring Cloud Gateway的源码,发现在org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint类中提供了动态配置的Rest接口,但是需要开启Gateway的端点,而且提供的功能不是很强大。通过参考和GatewayControllerEndpoint相关的代码,可以自己编码实际动态路由配置。
下面通过案例的方式去讲解怎么实现Gateway的动态路由配置。案例工程如ch18-7-gateway所示。

代码地址:https://github.com/SpringCloud/spring-cloud-code/blob/master/ch18-7/ch18-7-gateway

3. 简单动态路由的实现

3.1 新建Maven工程ch18-7-gateway

配置主要的核心依赖如代码清单18-33所示:
代码清单: ch18-7/ch18-7-gateway/pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

3.2 根据Spring Cloud Gateway的路由模型定义数据传输模型

分别创建GatewayRouteDefinition.java, GatewayPredicateDefinition.java, GatewayFilterDefinition.java这三个类。
(1) 创建路由定义模型如下代码清单18-34所示:
代码清单 18-34: ch18-7/ch18-7-gateway/src/main/java/cn/springcloud/book/gateway/model/GatewayRouteDefinition.java

1
2
3
4
5
6
7
8
9
10
11
12
13
public class GatewayRouteDefinition {
//路由的Id
private String id;
//路由断言集合配置
private List<GatewayPredicateDefinition> predicates = new ArrayList<>();
//路由过滤器集合配置
private List<GatewayFilterDefinition> filters = new ArrayList<>();
//路由规则转发的目标uri
private String uri;
//路由执行的顺序
private int order = 0;
//此处省略get和set方法
}

(2)创建过滤器定义模型,代码如代码清单18-35所示:
代码清单18-35: ch18-7/ch18-7-gateway/src/main/java/cn/springcloud/book/gateway/model/GatewayFilterDefinition.java

1
2
3
4
5
6
7
public class GatewayFilterDefinition {
//Filter Name
private String name;
//对应的路由规则
private Map<String, String> args = new LinkedHashMap<>();
//此处省略Get和Set方法
}

(3)路由断言定义模型,代码如代码清单18-36所示:
代码清单18-36: ch18-7/ch18-7-gateway/src/main/java/cn/springcloud/book/gateway/model/GatewayPredicateDefinition.java

1
2
3
4
5
6
7
public class GatewayPredicateDefinition {
//断言对应的Name
private String name;
//配置的断言规则
private Map<String, String> args = new LinkedHashMap<>();
//此处省略Get和Set方法
}

3.3 编写动态路由实现类

编写DynamicRouteServiceImpl并实现ApplicationEventPublisherAware接口,代码如代码清单18-37所示: ch18-37/ch18-7-gateway/src/main/java/cn/springcloud/book/gateway/route/DynamicRouteServiceImpl.java

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
@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
//增加路由
public String add(RouteDefinition definition) {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
}
//更新路由
public String update(RouteDefinition definition) {
try {
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
} catch (Exception e) {
return "update fail,not find route routeId: "+definition.getId();
}
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "success";
} catch (Exception e) {
return "update route fail";
}
}
//删除路由
public Mono<ResponseEntity<Object>> delete(String id) {
return this.routeDefinitionWriter.delete(Mono.just(id))
.then(Mono.defer(() -> Mono.just(ResponseEntity.ok().build())))
.onErrorResume(t -> t instanceof NotFoundException, t -> Mono.just(ResponseEntity.notFound().build()));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
}

3.4 编写Rest接口

编写RouteController类的提供Rest接口,用于动态路由配置。代码如代码清单18-38所示:
代码清单 18-38: ch18-7/ch18-7-gateway/src/main/java/cn/springcloud/book/gateway/controller/RouteController.java

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
@RestController
@RequestMapping("/route")
public class RouteController {
@Autowired
private DynamicRouteServiceImpl dynamicRouteService;
//增加路由
@PostMapping("/add")
public String add(@RequestBody GatewayRouteDefinition gwdefinition) {
try {
RouteDefinition definition = assembleRouteDefinition(gwdefinition);
return this.dynamicRouteService.add(definition);
} catch (Exception e) {
e.printStackTrace();
}
return "succss";
}
//删除路由
@DeleteMapping("/routes/{id}")
public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
return this.dynamicRouteService.delete(id);
}
//更新路由
@PostMapping("/update")
public String update(@RequestBody GatewayRouteDefinition gwdefinition) {
RouteDefinition definition = assembleRouteDefinition(gwdefinition);
return this.dynamicRouteService.update(definition);
}
}

3.5 配置application.yml文件

在application.yml文件配置应用的配置信息,并开启Spring Cloud Gateway对外提供的端点Rest接口。代码如代码清单18-39所示:
代码清单 18-39: ch18-7/ch18-7-gateway/src/main/resources/application.yml
配置输出日志如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 配置输出日志
logging:
level:
org.springframework.cloud.gateway: TRACE
org.springframework.http.server.reactive: DEBUG
org.springframework.web.reactive: DEBUG
reactor.ipc.netty: DEBUG
#开启端点
management:
endpoints:
web:
exposure:
include: '*'
security:
enabled: false

3.6 启动ch18-7-gateway应用测试

(1) 启动ch18-7-gateway应用之后,由于开启了端点,首先打开浏览器访问端点URL:
http://localhost:8080/actuator/gateway/routes ,查看路由信息返回为空,如下图所示:

空的路由信息

(2)打开PostMan,访问http://localhost:8080/route/add, 发起Post请求,如下图所示,返回success说明向Gateway增加路由配置成功。
动态添加路由成功

然后再打开PostMan访问端点URL:http://localhost:8080/actuator/gateway/routes ,
查看路由信息返回如下图所示,可以看到已经添加的路由配置。
路由端点返回结果

(3) 打开浏览器访问http://localhost:8080/jd, 可以正常转发https://www.jd.com/对应的京东商城首页。
(4) 通过访问http://localhost:8080/route/update, 对id为jd_route的路由更新配置,如下图所示:
更新路由配置

然后再访问路由端点URL,发现路由配置已经被更新,如下图所示:
查看路由端点

然后通过浏览器访问http://localhost:8080/taobao ,可以成功转发到淘宝网。
(5) 通过访问http: //localhost:8080/route/delete/jd_route,其中的id为路由对应的id,删除路由结果如下图所示:
删除路由成功

4.Spring Cloud Gateway推荐文章

Spring Cloud Gateway中的权重路由
Spring Cloud Gateway中的GatewayFilter和GlobalFilter
Spring Cloud Gateway只有Pre和POST两种类型的Filter
Spring Cloud Gateway基于服务发现的默认路由规则
Spring Cloud Gateway的Before路由断言工厂
Spring Cloud Gateway的After路由断言工厂
Spring Cloud Gateway揭秘之处理请求流程
Spring Cloud Gateway入门案例

5.《重新定义Spring Cloud实战》中的Spring Cloud Gateway

第17章Spring Cloud Gateway上篇399
17.1 Spring Cloud Gateway概述399
17.1.1 什么是Spring Cloud Gateway399
17.1.2 Spring Cloud Gateway的核心概念399
17.2 Spring Cloud Gateway的工作原理400
17.3 Spring Cloud Gateway入门案例401
17.4 Spring Cloud Gateway的路由断言404
17.4.1 After路由断言工厂404
17.4.2 Before路由断言工厂406
17.4.3 Between路由断言工厂406
17.4.4 Cookie路由断言工厂407
17.4.5 Header路由断言工厂408
17.4.6 Host路由断言工厂410
17.4.7 Method路由断言工厂411
17.4.8 Query路由断言工厂411
17.4.9 RemoteAddr路由断言工厂412
17.5 Spring Cloud Gateway的内置Filter413
17.5.1 AddRequestHeader过滤器工厂413
17.5.2 AddRequestParameter过滤器413
17.5.3 RewritePath过滤器414
17.5.4 AddResponseHeader过滤器415
17.5.5 StripPrefix过滤器416
17.5.6 Retry过滤器417
17.5.7 Hystrix过滤器418
17.6 本章小结420
第18章 Spring Cloud Gateway下篇421
18.1 Gateway基于服务发现的路由规则421
18.1.1 Gateway的服务发现路由概述421
18.1.2 服务发现的路由规则案例422
18.2 Gateway Filter和Global Filter425
18.2.1 Gateway Filter和Global Filter概述425
18.2.2 自定义Gateway Filter案例425
18.2.3 自定义Global Filter案例427
18.3 Spring Cloud Gateway实战428
18.3.1 Spring Cloud Gateway权重路由428
18.3.2 Spring Cloud Gateway中Https的使用技巧431
18.3.3 Spring Cloud Gateway集成Swagger436
18.3.4 Spring Cloud Gateway限流442
18.3.5 Spring Cloud Gateway的动态路由450
18.4 Spring Cloud Gateway源码篇458
18.4.1 Spring Cloud Gateway的处理流程458
18.4.2 Gateway中ServerWebExchange构建分析459
18.4.3 DispatcherHandler源码分析460
18.4.4 RoutePredicateHandlerMapping源码分析461
18.4.5 FilteringWebHandler源码分析462
18.4.6 执行Filter源码分析463
18.5 本章小结465

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
├── ch17-1
│ ├── ch17-1-1-gateway
│ ├── ch17-1-2-gateway
│ ├── ch17-1.iml
│ └── pom.xml
├── ch17-2
│ ├── ch17-2-1-gateway
│ ├── ch17-2-2-gateway
│ ├── ch17-2-3-gateway
│ ├── ch17-2-4-gateway
│ ├── ch17-2-5-gateway
│ ├── ch17-2-6-gateway
│ ├── ch17-2-7-gateway
│ ├── ch17-2-8-gateway
│ ├── ch17-2-9-gateway
│ ├── ch17-2-service
│ ├── ch17-2.iml
│ └── pom.xml
├── ch17-3
│ ├── ch17-3-1-gateway
│ ├── ch17-3-2-gateway
│ ├── ch17-3-3-gateway
│ ├── ch17-3-4-gateway
│ ├── ch17-3-5-gateway
│ ├── ch17-3-6-gateway
│ ├── ch17-3-7-gateway
│ ├── ch17-3-service
│ ├── ch17-3.iml
│ └── pom.xml
├── ch18-1
│ ├── ch18-1-consumer
│ ├── ch18-1-eureka
│ ├── ch18-1-gateway
│ ├── ch18-1-provider
│ ├── ch18-1.iml
│ └── pom.xml
├── ch18-2
│ ├── ch18-2-gateway
│ ├── ch18-2-provider
│ ├── ch18-2.iml
│ ├── pom.xml
│ └── reademe.txt
├── ch18-3
│ ├── ch18-3-gateway
│ ├── ch18-3-provider
│ ├── ch18-3.iml
│ └── pom.xml
├── ch18-4
│ ├── ch18-4-eureka
│ ├── ch18-4-gateway-https
│ ├── ch18-4-service-a
│ ├── ch18-4-service-b
│ ├── ch18-4.iml
│ ├── pom.xml
│ └── reademe.md
├── ch18-5
│ ├── ch18-5-eureka
│ ├── ch18-5-gateway
│ ├── ch18-5-service
│ ├── ch18-5.iml
│ └── pom.xml
├── ch18-6
│ ├── ch18-6-1-gateway
│ ├── ch18-6-2-gateway
│ ├── ch18-6-3-gateway
│ ├── ch18-6-provider
│ ├── ch18-6.iml
│ └── pom.xml
├── ch18-7
│ ├── ch18-7-gateway
│ ├── ch18-7.iml
│ ├── pom.xml
│ └── readme.md

Spring Cloud Gateway所有示例代码地址:https://github.com/SpringCloud/spring-cloud-code

如果您觉得文章不错,可以打赏我喝一杯咖啡!