SpringCloudGateway开发过程解析

 更新时间:2019年12月02日 08:27:47   作者:saozhou  
这篇文章主要介绍了SpringCloudGateway开发过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

路由简介:

1.SpringCloudGateWay 是用于替代zuul作为API网关,在gateway中有三个重要的名词:过滤器,断言,路由

过滤器与断言是路由的一部分,路由便是将请求进行一系列的处理后分发到各个服务的一个过程。

路由的过程:首先会加载断言以及路由,在接受到请求后根据断言加载的顺序会匹配到先加载的断言,只有与断言匹配了的请求才会进入路由,没有匹配到的服务会将请求当成普通的访问请求。

2:路由加载断言的方式:

断言加载的方式有四种,分别是配置文件,java编码,数据库以及注册中心

第一种配置文件:

在官方文档中主要介绍的就是配置文件的加载方式

官方地址:https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-starter

一般的断言有三种要素:id,uri,predicate.

id是断言的标识,uri是ip+端口,predicate则是断言匹配的规则

3:示例:

新建一个springboot项目,并且引入springcloudgateway的依赖

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
  </dependencies>

在启动类注册三个全局过滤器

@SpringBootApplication
public class GateWayApplication {

  public static void main(String[] args) {
    SpringApplication.run(GateWayApplication.class, args);
  }

  @Bean
  @Order(-1)
  public GlobalFilter a() {
    return (exchange, chain) -> {

      return chain.filter(exchange).then(Mono.fromRunnable(() -> {
        System.out.println(-1);
      }));
    };
  }

  @Bean
  @Order(0)
  public GlobalFilter b() {
    return (exchange, chain) -> {

      return chain.filter(exchange).then(Mono.fromRunnable(() -> {
        System.out.println(0);
      }));
    };
  }

  @Bean
  @Order(1)
  public GlobalFilter c() {
    return (exchange, chain) -> {

      return chain.filter(exchange).then(Mono.fromRunnable(() -> {
        System.out.println(1);
      }));
    };
  }
}

在配置文件类配置两条路由

server.port: 7777
spring:
 application:
  name: gateway
 cloud:
  gateway:
   discovery:
    locator:
     enabled: true
     lower-case-service-id: true
   routes:
   - id: method_route
    uri: http://127.0.0.1:9999
    predicates:
    - Method=GET
   - id: method_route
    uri: http://127.0.0.1:8006
    predicates:
    - Method=GET


发送请求,请求到达后匹配的是第一条路由,由此可以知道路由匹配的顺序会根据加载的顺序来

4:SpringCloudGateWay从注册中心获得路由

在官方文档中,我们可以看到有这样的一段话

Configuring Predicates and Filters For DiscoveryClient Routes

By default the Gateway defines a single predicate and filter for routes created via a DiscoveryClient.

The default predicate is a path predicate defined with the pattern /serviceId/**, where serviceId is the id of the service from the DiscoveryClient.

The default filter is rewrite path filter with the regex /serviceId/(?<remaining>.*) and the replacement /${remaining}. This just strips the service id from the path before the request is sent downstream.

If you would like to customize the predicates and/or filters used by the DiscoveryClient routes you can do so by setting spring.cloud.gateway.discovery.locator.predicates[x] and spring.cloud.gateway.discovery.locator.filters[y]. When doing so you need to make sure to include the default predicate and filter above, if you want to retain that functionality. Below is an example of what this looks like.

地址 :https://cloud.spring.io/spring-cloud-gateway/reference/html/#_global_filters

spring.cloud.gateway.discovery.locator.predicates[0].name: Path
spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
spring.cloud.gateway.discovery.locator.predicates[1].name: Host
spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix
spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/(?<remaining>.*)'"
spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"

根据文档介绍,依照这种方式,可以从注册中心获得断言与过滤器的配置

5:SpringGateWay从数据库配置路由

public class DBRouteDefinitionRepository implements RouteDefinitionRepository

项目中实现了RouteDefinitionRepository后,springgateway会采用你实现的这个类去加载路由,如果不实现则采用他默认的方式加载路由

public class DBRouteDefinitionRepository implements RouteDefinitionRepository {
  //保存路由
  private final Map<String, RouteDefinition> routes = synchronizedMap(new LinkedHashMap<String, RouteDefinition>());
  
  private Logger log = LoggerFactory.getLogger(DBRouteDefinitionRepository.class);
  //初始標準
  private boolean init_flag = true;
  //
  private final GatewayProperties properties;
  private DynamicRouteServiceImpl service;
  

  public DBRouteDefinitionRepository(GatewayProperties properties) {
    this.properties = properties;
    this.service = new DynamicRouteServiceImpl();

  }
  
  @Override
  public Flux<RouteDefinition> getRouteDefinitions() {
    if(init_flag) {
      List<RouteDefinition> routeDefinitions = new ArrayList<>();
      List<RouteDefinition> rs = new ArrayList<>();
      try {
        routeDefinitions = service.quertAllRoutes();//从数据库中加载route
        rs = this.properties.getRoutes();//获得配置文件的route
        for (RouteDefinition rse : rs) {
          routeDefinitions.add(rse);
        }
        routes.clear();
        routeDefinitions.forEach(x->routes.put(x.getId(), x));
        init_flag=false;
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        log.error("Init Route Fail,Can't get Routes.",e);
      }
      return Flux.fromIterable(routeDefinitions);
    }else {
      return Flux.fromIterable(routes.values());
    }
    
  }

  @Override
  public Mono<Void> delete(Mono<String> routeId) {
    return routeId.flatMap(id -> {
      if (routes.containsKey(id)) {
        routes.remove(id);
        return Mono.empty();
      }
      return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: "+routeId)));
    });
  }

  @Override
  public Mono<Void> save(Mono<RouteDefinition> route) {
    return route.flatMap( r -> {
      routes.put(r.getId(), r);
      return Mono.empty();
    });
  }
}

这个是我自己实现的类,这个类可以从数据库与配置文件中获得路由配置,从数据库中获得路由配置可以根据个人的要求来

@Validated
public class RouteDefinition {

  @NotEmpty
  private String id = UUID.randomUUID().toString();

  @NotEmpty
  @Valid
  private List<PredicateDefinition> predicates = new ArrayList<>();

  @Valid
  private List<FilterDefinition> filters = new ArrayList<>();

  @NotNull
  private URI uri;

  private int order = 0;

  public RouteDefinition() {
  }

  public RouteDefinition(String text) {
    int eqIdx = text.indexOf('=');
    if (eqIdx <= 0) {
      throw new ValidationException("Unable to parse RouteDefinition text '" + text
          + "'" + ", must be of the form name=value");
    }

    setId(text.substring(0, eqIdx));

    String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

    setUri(URI.create(args[0]));

    for (int i = 1; i < args.length; i++) {
      this.predicates.add(new PredicateDefinition(args[i]));
    }
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public List<PredicateDefinition> getPredicates() {
    return predicates;
  }

  public void setPredicates(List<PredicateDefinition> predicates) {
    this.predicates = predicates;
  }

  public List<FilterDefinition> getFilters() {
    return filters;
  }

  public void setFilters(List<FilterDefinition> filters) {
    this.filters = filters;
  }

  public URI getUri() {
    return uri;
  }

  public void setUri(URI uri) {
    this.uri = uri;
  }

  public int getOrder() {
    return order;
  }

  public void setOrder(int order) {
    this.order = order;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    RouteDefinition routeDefinition = (RouteDefinition) o;
    return Objects.equals(id, routeDefinition.id)
        && Objects.equals(predicates, routeDefinition.predicates)
        && Objects.equals(order, routeDefinition.order)
        && Objects.equals(uri, routeDefinition.uri);
  }

  @Override
  public int hashCode() {
    return Objects.hash(id, predicates, uri);
  }

  @Override
  public String toString() {
    return "RouteDefinition{" + "id='" + id + '\'' + ", predicates=" + predicates
        + ", filters=" + filters + ", uri=" + uri + ", order=" + order + '}';
  }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot使用Flyway进行数据库管理的操作方法

    SpringBoot使用Flyway进行数据库管理的操作方法

    Flyway是一个开源的数据库版本管理工具,并且极力主张“约定大于配置”,简单、专注、强大。接下来通过本文给大家介绍SpringBoot使用Flyway进行数据库管理的方法,感兴趣的朋友一起看看吧
    2021-09-09
  • Java模拟有序链表数据结构的示例

    Java模拟有序链表数据结构的示例

    这篇文章主要介绍了Java模拟有序链表数据结构的示例,包括一个反序的单链表结构的例子,需要的朋友可以参考下
    2016-04-04
  • Java中的锁分类的详细介绍

    Java中的锁分类的详细介绍

    这篇文章主要介绍了Java中的锁分类的详细介绍,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • java验证码生成的基本流程

    java验证码生成的基本流程

    这篇文章主要介绍了java验证码生成的基本流程,需要的朋友可以参考下
    2015-11-11
  • LibrarySystem图书管理系统(二)

    LibrarySystem图书管理系统(二)

    这篇文章主要为大家详细介绍了LibrarySystem图书管理系统开发第二篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Java调用wsdl接口的两种方法(axis和wsimport)

    Java调用wsdl接口的两种方法(axis和wsimport)

    本文主要介绍了Java调用wsdl接口的两种方法(axis和wsimport),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • SpringBoot整合ShardingSphere的示例代码

    SpringBoot整合ShardingSphere的示例代码

    本文主要介绍了SpringBoot整合ShardingSphere的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Java中Switch的使用方法及新特性

    Java中Switch的使用方法及新特性

    在java中控制流程语句是由选择语句、循环语句、跳转语句构成,选择语句包括if和switch,在过多的使用if语句嵌套会使程序很难阅读,这时就可以用到switch语句,这篇文章主要给大家介绍了关于Java中Switch的使用方法及新特性的相关资料,需要的朋友可以参考下
    2023-11-11
  • 使用Swagger时Controller中api接口显示不全的问题分析及解决

    使用Swagger时Controller中api接口显示不全的问题分析及解决

    swagger是一个十分好用的api接口管理、测试框架,现在越来越多的人使用这个做接口的测试和管理,但经常遇到Controller中的api接口显示不全的问题,所以本文给大家详细分析了问题以及解决方法,需要的朋友可以参考下
    2024-02-02
  • Java算法之BFS,DFS,动态规划和贪心算法的实现

    Java算法之BFS,DFS,动态规划和贪心算法的实现

    广度优先搜索(BFS)和深度优先搜索(DFS)是图遍历算法中最常见的两种算法,主要用于解决搜索和遍历问题。动态规划和贪心算法则用来解决优化问题。本文就来看看这些算法的具体实现吧
    2023-04-04

最新评论