59

Spring Cloud Gateway的动态路由实现

 5 years ago
source link: http://xujin.org/sc/gw/gw09/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

网关中有两个重要的概念,那就是路由配置和路由规则,路由配置是指配置某请求路径路由到指定的目的地址。而路由规则是指匹配到路由配置之后,再根据路由规则进行转发处理。

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

<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

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

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

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

@Service
public class DynamicRouteServiceImplimplements 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

@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

配置输出日志如下所示:

# 配置输出日志
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 ,查看路由信息返回为空,如下图所示:

73i6zqm.png!web

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

myUvyuq.png!web

然后再打开PostMan访问端点URL: http://localhost:8080/actuator/gateway/routes ,

查看路由信息返回如下图所示,可以看到已经添加的路由配置。

EFbauyZ.png!web

(3) 打开浏览器访问 http://localhost:8080/jd , 可以正常转发 https://www.jd.com/对应的京东商城首页。

(4) 通过访问 http://localhost:8080/route/update , 对id为jd_route的路由更新配置,如下图所示:

bIB3yy2.png!web

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

VBbIzqj.png!web

然后通过浏览器访问 http://localhost:8080/taobao ,可以成功转发到淘宝网。

(5) 通过访问http: //localhost:8080/route/delete/jd_route,其中的id为路由对应的id,删除路由结果如下图所示:

Anuyim3.png!web

4.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

├── 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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK