千家信息网

如何配置spring cloud 2.x版本Gateway动态路由

发表于:2024-11-25 作者:千家信息网编辑
千家信息网最后更新 2024年11月25日,本篇内容主要讲解"如何配置spring cloud 2.x版本Gateway动态路由",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何配置spring c
千家信息网最后更新 2024年11月25日如何配置spring cloud 2.x版本Gateway动态路由

本篇内容主要讲解"如何配置spring cloud 2.x版本Gateway动态路由",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何配置spring cloud 2.x版本Gateway动态路由"吧!

spring cloud 2.x版本 Gateway动态路由教程

摘要

本文采用的Spring cloud为2.1.8RELEASE,version=Greenwich.SR3

前言

写了几篇关于Spring Cloud Gateway的文章后发现,Gateway涉及的知识范围太广了,真是深刻体会了"一入Spring cloud深似海"。

现实生产环境中,使用Spring Cloud Gateway都是作为所有流量的入口,为了保证系统的高可用,尽量避免系统的重启,所以需要Spring Cloud Gateway的动态路由来处理。之前的文章《Gateway路由网关教程》提供的路由配置,在系统启动时候,会将路由配置和规则加载到内存当中,无法做到不重启服务就可以动态的新增、修改、删除内存中的路由配置和规则。

简单的动态路由实现

Spring Cloud Gateway源码中提供了GatewayControllerEndpoint类来修改路由配置,但是官方文档好像并没有做详细的使用说明,只是简单介绍了几个简单的api接口。感兴趣的小伙伴可以先查看官方文档(第11章节 Actuator API)。

引致官方文档:

The /gateway actuator endpoint allows to monitor and interact with a Spring Cloud Gateway application. To be remotely accessible, the endpoint has to be enabled and exposed via HTTP or JMX in the application properties.

1.1 添加相关pom依赖

在原来spring-gateway的基础上增加spring-boot-starter-actuator依赖

    org.springframework.boot    spring-boot-starter-actuator

1.2 在application.yml中增加配置

management:  endpoints:    web:      exposure:        include: "*"

配置说明:management.endpoints.web.exposure.include 暴露所有的gateway端点

1.3 启动服务

启动服务,访问http://localhost:8100/actuator/gateway/routes,这是我们可以看到所有的routes信息。 image-20191102225203034.png 我们也可以访问单个路由信息:http://localhost:8100/actuator/gateway/routes/CompositeDiscoveryClient_EUREKA-CLIENT

显示如下:image-20191102225853005.png

1.4 增加、修改路由信息

Gateway默认使用的是GatewayControllerEndpoint这个类,GatewayControllerEndpoint又继承了AbstractGatewayControllerEndpoint类。

提供的方法:(只列具了几个相关方法,其他方法小伙们可以自行查看源码)

  1. /gateway/routes 查询所有路由信息

  2. /gateway/routes/{id} 根据路由id查询单个信息

  3. /gateway/routes/{id} @PostMapping 新增一个路由信息

  4. /gateway/routes/{id} @DeleteMapping 删除一个路由信息

1.4.1 新增路由

我们可根据/gateway/routes返回的路由信息,来模仿一个@PostMapping请求参数

{    "uri": "http://httpbin.org:80",    "predicates": [        {            "args": {                "pattern": "/ribbon/**"            },            "name": "Path"        }    ],    "filters": []}

这是我们可以通过postman来发送一个post请求,如图所示:

response返回1证明已经插入成功,我们可以通过http://localhost:8100/actuator/gateway/routes/查看路由信息,显示结果如下:

截图红框中的信息就是新增加的

1.4.2 删除路由信息

我们可以直接用postman模拟DeleteMapping请求,http://localhost:8100/actuator/gateway/routes/addroutes

显示如下:

这时候我们在访问http://localhost:8100/actuator/gateway/routes,可以看到新增加的路由已经被删除成功了。

1.5 小结

基于Spring Cloud Gateway默认方法实现的动态路由我就完成了,在前言中我已经提到了,这种方式是基于jvm内存实现,一旦服务重启,新增的路由配置信息就是完全消失了。所有这个时候我们可以考虑是否可以参考GatewayControllerEndpoint这类,自己实现一套动态路由方法,然后将路由信息持久化。

自定义动态路由

1.1定义相关类

1.1.1 定义实体类

可以自定义实体类,我这里偷了一个懒,直接用了Gateway的RouteDefinition类,感兴趣的小伙伴可以参考RouteDefinition类自己扩展,然后写一个Convert类将自定义的类转换成RouteDefinition就可以了。

1.1.2 自定义RedisRouteDefinitionRepository类

我这边采用redis做为路由配置的信息的持久层,所以写了一个RedisRouteDefinitionRepository。

package spring.cloud.demo.spring.gateway.component;import com.google.common.collect.Lists;import org.springframework.cloud.gateway.route.RouteDefinition;import org.springframework.cloud.gateway.route.RouteDefinitionRepository;import org.springframework.cloud.gateway.support.NotFoundException;import org.springframework.stereotype.Component;import reactor.core.publisher.Flux;import reactor.core.publisher.Mono;import spring.cloud.demo.spring.gateway.redis.RedisUtils;import spring.cloud.demo.spring.gateway.util.JsonUtils;import javax.annotation.Resource;import java.util.List;/** * @auther: maomao * @DateT: 2019-11-03 */@Componentpublic class RedisRouteDefinitionRepository implements RouteDefinitionRepository {    //存储的的key    private final static String KEY = "gateway_dynamic_route";    @Resource    private RedisUtils redisUtils;    /**     * 获取路由信息     * @return     */    @Override    public Flux getRouteDefinitions() {        List gatewayRouteEntityList = Lists.newArrayList();        redisUtils.hgets(KEY).stream().forEach(route -> {            RouteDefinition result = JsonUtils.parseJson(route.toString(), RouteDefinition.class);            gatewayRouteEntityList.add(result);        });        return Flux.fromIterable(gatewayRouteEntityList);    }    /**     * 新增     * @param route     * @return     */    @Override    public Mono save(Mono route) {        return route.flatMap(routeDefinition -> {            redisUtils.hset(KEY, routeDefinition.getId(), JsonUtils.toString(routeDefinition));            return Mono.empty();        });    }    /**     * 删除     * @param routeId     * @return     */    @Override    public Mono delete(Mono routeId) {        return routeId.flatMap(id -> {            if (redisUtils.hHashKey(KEY, id)) {                redisUtils.hdel(KEY, id);                return Mono.empty();            }            return Mono.defer(() -> Mono.error(new NotFoundException("route definition is not found, routeId:" + routeId)));        });    }}
1.1.3 自定义Controller和Service
package spring.cloud.demo.spring.gateway.controller;import lombok.extern.slf4j.Slf4j;import org.springframework.cloud.gateway.route.RouteDefinition;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.DeleteMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import reactor.core.publisher.Mono;import spring.cloud.demo.spring.gateway.service.GatewayDynamicRouteService;import javax.annotation.Resource;/** * 自定义动态路由 * @auther: maomao * @DateT: 2019-11-03 */@RestController@RequestMapping("/gateway")@Slf4jpublic class GatewayDynamicRouteController {    @Resource    private GatewayDynamicRouteService gatewayDynamicRouteService;    @PostMapping("/add")    public String create(@RequestBody RouteDefinition entity) {        int result = gatewayDynamicRouteService.add(entity);        return String.valueOf(result);    }    @PostMapping("/update")    public String update(@RequestBody RouteDefinition entity) {        int result = gatewayDynamicRouteService.update(entity);        return String.valueOf(result);    }    @DeleteMapping("/delete/{id}")    public Mono> delete(@PathVariable String id) {        return gatewayDynamicRouteService.delete(id);    }}
package spring.cloud.demo.spring.gateway.service;import org.springframework.cloud.gateway.event.RefreshRoutesEvent;import org.springframework.cloud.gateway.route.RouteDefinition;import org.springframework.cloud.gateway.support.NotFoundException;import org.springframework.context.ApplicationEventPublisher;import org.springframework.context.ApplicationEventPublisherAware;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Service;import reactor.core.publisher.Mono;import spring.cloud.demo.spring.gateway.component.RedisRouteDefinitionRepository;import javax.annotation.Resource;/** * @auther: maomao * @DateT: 2019-11-03 */@Servicepublic class GatewayDynamicRouteService implements ApplicationEventPublisherAware {    @Resource    private RedisRouteDefinitionRepository redisRouteDefinitionRepository;    private ApplicationEventPublisher applicationEventPublisher;    /**     * 增加路由     * @param routeDefinition     * @return     */    public int add(RouteDefinition routeDefinition) {        redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));        return 1;    }    /**     * 更新     * @param routeDefinition     * @return     */    public int update(RouteDefinition routeDefinition) {        redisRouteDefinitionRepository.delete(Mono.just(routeDefinition.getId()));        redisRouteDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));        return 1;    }    /**     * 删除     * @param id     * @return     */    public Mono> delete(String id) {        return redisRouteDefinitionRepository.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.applicationEventPublisher = applicationEventPublisher;    }}

1.2 application.yml

application.yml配置要暴漏Gateway的所有端点,可以看考之前的配置信息。

1.3 启动服务

启动Spring cloud Gateway服务,先访问http://localhost:8100/actuator/gateway/routes,查看已有的路由配置信息。然后我们用postman请求add方法,http://localhost:8100/gateway/add,如果所示:

注意截图中红框的内容。证明已经新增成功。

这时我们在访问http://localhost:8100/actuator/gateway/routes查看结果。如果所示:

同理我们可以访问update和delete方法,我这里就不过多描述了。

总结

自定义动态路由核心原理其实就要重写网关模块,也就是之前提到的RedisRouteDefinitionRepository类。我这里偷懒没有重新定义对应的实体类,这里需要注意的是,传入参数一定要按照application.yml中配置的格式,然后转成json,如果格式不正确会报错。

代码地址

gitHub地址


《Srping Cloud 2.X小白教程》目录

  • spring cloud 2.x版本 Eureka Server服务注册中心教程

  • spring cloud 2.x版本 Eureka Client服务提供者教程

  • spring cloud 2.x版本 Ribbon服务发现教程(内含集成Hystrix熔断机制)

  • spring cloud 2.x版本 Feign服务发现教程(内含集成Hystrix熔断机制)

  • spring cloud 2.x版本 Zuul路由网关教程

  • spring cloud 2.x版本 config分布式配置中心教程

  • spring cloud 2.x版本 Hystrix Dashboard断路器教程

  • spring cloud 2.x版本 Gateway路由网关教程

  • spring cloud 2.x版本 Gateway自定义过滤器教程

  • spring cloud 2.x版本 Gateway熔断、限流教程


    • spring cloud 2.x版本 Gateway动态路由教程


到此,相信大家对"如何配置spring cloud 2.x版本Gateway动态路由"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0