SpringCloud微服务API网关Gateway的使用和配置(三)动态路由

目录

  • 一、介绍
  • 二、代码实现
    • 2.1 根据Spring Cloud Gateway的路由模型定义数据传输模型
    • 2.2 编写动态路由实现类
    • 2.3 编写 Rest接口
  • 三、测试
    • 添加路由:
    • 更新路由:
    • 删除路由:
  • 码源
  • 参考文章

一、介绍

在实际生产环境中为了保证高可靠和高可用,尽量避免重启,如果有新的服务要上线时,可以通过动态路由配置功能上线。
Gateway配置路由主要有两种方式:

  1. 用yml配置文件,
  2. 写在代码里。

而无论是 yml,还是代码配置,启动网关后将无法修改路由配置,如有新服务要上线,则需要先把网关下线,修改 yml 配置后,再重启网关

二、代码实现

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

package org.springframework.cloud.gateway.route :
SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第1张图片

路由模型:

@Data
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;
}

过滤器模型:

@Data
public class GatewayFilterDefinition {

    //Filter Name
    private String name;
    //对应的路由规则
    private Map<String, String> args = new LinkedHashMap<>();
}

断言模型:

@Data
public class GatewayPredicateDefinition {
    //断言对应的Name
    private String name;
    //配置的断言规则
    private Map<String, String> args = new LinkedHashMap<>();
}

2.2 编写动态路由实现类

编写动态路由实现类,需实现ApplicationEventPublisherAware接口

@Service
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

    @Autowired
    private RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }


    //增加路由
    public String add(RouteDefinition definition) {
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "add route success";
    }

    //更新路由
    public String update(RouteDefinition definition) {
        try {
            delete(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 "update route 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(() -> {
            return Mono.just(ResponseEntity.ok().build());
        })).onErrorResume((t) -> {
            return t instanceof NotFoundException;
        }, (t) -> {
            return Mono.just(ResponseEntity.notFound().build());
        });
    }



}

2.3 编写 Rest接口

编写 Rest接口,通过这些接口实现动态路由功能,注意SpringCloudGateway使用的是WebFlux不要引用WebMvc。

@RestController
@RequestMapping("/route")
public class RouteController {

    @Autowired
    private DynamicRouteServiceImpl dynamicRouteService;

    //增加路由
    @PostMapping("/add")
    public String add(@RequestBody GatewayRouteDefinition gwdefinition) {
        String flag = "fail";
        try {
            RouteDefinition definition = assembleRouteDefinition(gwdefinition);
            flag = this.dynamicRouteService.add(definition);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }
    //删除路由 Mono>
    @DeleteMapping("/routes/{id}")
    public Mono<ResponseEntity<Object>> delete(@PathVariable String id) {
        try {
            return this.dynamicRouteService.delete(id);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    //更新路由
    @PostMapping("/update")
    public String update(@RequestBody GatewayRouteDefinition gwdefinition) {
        RouteDefinition definition = assembleRouteDefinition(gwdefinition);
        return this.dynamicRouteService.update(definition);
    }

    //把传递进来的参数转换成路由对象
    private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(gwdefinition.getId());
        definition.setOrder(gwdefinition.getOrder());

        //设置断言
        List<PredicateDefinition> pdList=new ArrayList<>();
        List<GatewayPredicateDefinition> gatewayPredicateDefinitionList=gwdefinition.getPredicates();
        for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {
            PredicateDefinition predicate = new PredicateDefinition();
            predicate.setArgs(gpDefinition.getArgs());
            predicate.setName(gpDefinition.getName());
            pdList.add(predicate);
        }
        definition.setPredicates(pdList);

        //设置过滤器
        List<FilterDefinition> filters = new ArrayList();
        List<GatewayFilterDefinition> gatewayFilters = gwdefinition.getFilters();
        for(GatewayFilterDefinition filterDefinition : gatewayFilters){
            FilterDefinition filter = new FilterDefinition();
            filter.setName(filterDefinition.getName());
            filter.setArgs(filterDefinition.getArgs());
            filters.add(filter);
        }
        definition.setFilters(filters);

        URI uri = null;
        if(gwdefinition.getUri().startsWith("http")){
            uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();
        }else{
            // uri为 lb://consumer-service 时使用下面的方法
            uri = URI.create(gwdefinition.getUri());
        }
        definition.setUri(uri);
        return definition;
    }
}

三、测试

添加路由:

URL : http://localhost:9004/route/add

参数:

{
    "id": "routeadd",
    "predicates": [
        {
            "name": "Path",
            "args": {
                "pattern": "/ccc/**"
            }
        }
    ],
    "filters": [
        {
            "name": "StripPrefix",
            "args": {
                "parts": "1"
            }
        },
        {
            "name":"RequestPath",
            "args":{
                "name":"lisi",
                "path":"/baidu"
            }
        }
    ],
    "uri": "https://www.baidu.com",
    "order": 1
}

SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第2张图片

SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第3张图片

Spring Cloud Gateway 提供了 Endpoint 端点,暴露路由信息,有获取所有路由、刷新路由、查看单个路由、删除路由等方法,源码在 org.springframework.cloud.gateway.actuate.GatewayControllerEndpoint 中,想访问端点中的方法需要添加 spring-boot-starter-actuator 注解,并在配置文件中暴露所有端点。

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
        <!-- actuator是监控系统健康情况的工具。-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
# 暴露端点  需要添加 actuator 依赖, 有获取所有路由、刷新路由、查看单个路由、删除路由等方法
# http://localhost:9004/actuator/gateway/routes  查看application.yml中的Gateway的routes信息
management:
  endpoints:
    web:
      exposure:
        include: '*'
  endpoint:
    health:
      show-details: always

SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第4张图片

更新路由:

URL:http://localhost:9004/route/update
Path的断言参数由/ccc/**修改为/bbb/**
参数:

{
    "id": "routeadd",
    "predicates": [
        {
            "name": "Path",
            "args": {
                "pattern": "/bbb/**"
            }
        }
    ],
    "filters": [
        {
            "name": "StripPrefix",
            "args": {
                "parts": "1"
            }
        },
        {
            "name":"RequestPath",
            "args":{
                "name":"lisi",
                "path":"/baidu"
            }
        }
    ],
    "uri": "https://www.baidu.com",
    "order": 1
}

SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第5张图片
SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第6张图片

SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第7张图片

删除路由:

URL: http://localhost:9004/route/routes/routeadd

再次请求404:
SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第8张图片

通过actuator查询也已经删除:
SpringCloud微服务API网关Gateway的使用和配置(三)动态路由_第9张图片

码源

https://gitee.com/L1692312138/spring-cloud-alibaba

参考文章

https://blog.csdn.net/zhuyu19911016520/article/details/86557165

你可能感兴趣的:(SpringCloud,网关,spring,boot,spring,java)