gateway 订阅
Gateway是一家1985年成立于美国爱荷华州的公司,现成长为美国知名的PC品牌,2007年10月被Acer宏碁以7.1亿美元收购该公司。Gateway公司的品牌产品已经通过主要零售商、电子零售商和渠道合作伙伴进入美国、墨西哥、加拿大、日本、中国以及越来越多的亚太地区市场。 展开全文
Gateway是一家1985年成立于美国爱荷华州的公司,现成长为美国知名的PC品牌,2007年10月被Acer宏碁以7.1亿美元收购该公司。Gateway公司的品牌产品已经通过主要零售商、电子零售商和渠道合作伙伴进入美国、墨西哥、加拿大、日本、中国以及越来越多的亚太地区市场。
信息
成立时间
1985年
公司名称
捷威
总部地点
美国南加利福尼亚州
公司类型
股份公司
外文名称
Gateway
经营范围
IT产品
Gateway电脑品牌
Gateway (中文商标:捷威)于 1985 年在美国中西部的一间农舍里创立,已经成长为世界最知名的技术品牌之一,拥有数百万满意的客户。公司创始人泰德-温特(Ted Waitt) 以他祖母向银行担保的 10,000 美元贷款、一台租赁的计算机和一份三页的经营计划起家,将 Gateway 发展成了一个具有革命性意义的公司,它的创新改变了技术产业的面貌。1991 年,公司(原名 Gateway 2000)推出了彰显其牧场起家背景的别具一格的奶牛花斑盒状商标,获得了全国消费者的认可。1993 年,它进入财富 500 强并在 纳斯达克(NASDAQ)上市,随后,在 1997 年转到纽约证券交易所。第二年,Gateway 将其总部从南达科他州的 North Sioux City 迁到了南加利福尼亚州。2004 年 3 月,Gateway 收购了世界上成长最快、效率最高的 PC 制造商之一eMachines。eMachines 是美国第二大个人计算机零售品牌,以低价PC 为主营业务,其技术支持和质量屡获殊荣。 2004年9月,公司将总部迁至加州Irvine。Gateway在中国大陆的昵称为花斑奶牛。 [1]  在创业初期, Gateway开创了业内多个第一。它是第一个提供彩色显示器系统的PC公司,也是第一个提供三年质保的公司,同时也是第一个整合PC和电视功能的厂商。它是直销知名电子消费品并获得成功的公司之一。Gateway是美国第二大PC厂商,居世界前10名。公司的eMachines品牌由国内的著名零售巨头独家销售,而 Gateway的增值产品则通过电话、网络以及直销力量向主要的零售厂商提供。Gateway尊重客户,关注于服务品质和价值的提升。在客户忠诚度方面,其连续多年居于业内之首。2007 年 10 月,Gateway 被总部设在台湾的宏碁公司 (Acer Inc.) 收购,收购后的联合实体现已成为世界第三大 PC 公司。 [2]  2008年,Gateway团队操盘宏碁全球台式机业务,宏碁对台式机业务有更高的期望值,Gateway团队对台式机又有较强的研发及市场经验,因此,决定由GateWay公司的团队操盘其全球台式机业务。Gateway 始终致力追求让客户在购买、拥有和使用 PC 时感到方便无忧这一境界。在 Gateway 向新市场迈进的过程中,公司将继续坚持其最初的目标:通过技术帮助人们提高生活品质。Gateway 产品由指定零售合作伙伴销售。上海市黄浦区西藏中路168号都市总部大厦3楼(200001)2010Gateway 品牌 品牌 电脑报 5月 最佳服务奖Gateway 笔记本 NV49C 中国电脑教育报 6月28日 暑期档最佳产品Gateway 笔记本 NV49C 微型计算机 11月 BUST SHOPPING Gateway产品(4张) Gateway 笔记本 NV49C83C 电脑报 12月20日 2010年度推荐奖Gateway 笔记本 NV4435c 中关村在线 12月 2010年度推荐产品Gateway 台式机 FX6840-000C 中关村在线 12月 2010年度推荐产品Gateway 笔记本 NV59C PConline 12月27日 最佳外观奖Gateway 笔记本 EC39C PConline 12月27日 最佳外观奖Gateway 超便携笔记本 LT3115c PConline 12月27日 编辑选择奖Gateway 笔记本 EC39C PCPOP 12月30日 最佳设计奖Gateway 笔记本 ID49C IT168 1月5日 2010年度产品奖Gateway 笔记本 EC39C 6月 台北国际计算机展2010创新设计奖Gateway 笔记本 EC39C 10月 2010日本优良设计奖Gateway 显示器 FHD2303L 10月 2010日本优良设计奖Gateway 显示器 FHD2303L 12月 iF Product Design Award 产品设计奖Packard Bell笔记本 EasyNote Butterfly 12月 iF Product Design Award 产品设计奖 GTW EC39C与其同样模具Gateway 台式机 FX系列 12月 2011年CES创新与工程设计大奖
收起全文
精华内容
下载资源
问答
  • Gateway

    2020-03-04 18:14:58
    Gateway核心概念 Gateway入门和实战 网关统一限流 网关服务核心业务功能剖析 ------------------------------------- Gateway核心概念 一:什么是SpringCloud gateWay Spring Cloud Gateway是Spring Cloud...

    目录:

    Gateway 核心概念

    Gateway 入门和实战

    网关统一限流(下次补)

    网关服务核心业务功能剖析(下次补)

    -------------------------------------

    Gateway 核心概念

    一:什么是SpringCloud gateWay
    Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul
    网关。网关作为流量的,在微服务系统中有着非常作用。据说性能是第一代网关
    zuul的1.5倍。(基于Netty,WebFlux),
    注意点:由于不是Sevlet容器,所以他不能打成war包, 只支持SpringBoot2.X不
    支持1.x
    1.1)网关作用:
    网关常见的功能有路由转发、权限校验、限流控制等作用。
     

    Gateway 入门和实战

    1.加入Maven依赖

    <dependencies> 
     <dependency> 
     <groupId>org.springframework.cloud</groupId> 
     <artifactId>spring‐cloud‐starter‐gateway</artifactId> 
     </dependency> 
     <!‐‐加入nacos的依赖‐‐> 
     <dependency> 
     <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring‐cloud‐alibaba‐nacos‐discovery</artifactId> 
      </dependency> 
      <dependency> 
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring‐boot‐starter‐actuator</artifactId> 
     </dependency>

    2.相关配置

    #规划GateWay的服务端口 
    server: 
    port: 8888 
    #规划gateWay注册到到nacos上的服务应用名称 
     spring: 
     application: 
     name: api‐gateway 
     cloud: 
     nacos: 
     discovery: 
     #gateway工程注册到nacos上的地址
     server‐addr: localhost:8848 
      gateway: 
      discovery: 
      locator: 
      #开启gateway从nacos上获取服务列表 
      enabled: true 
      #开启acutor端点 
      management: 
      endpoints:
     web: 
     exposure: 
     include: '*' 
     endpoint:
     health: 
     #打开端点详情 
     show‐details: always

     

    3.启动程序

    @SpringBootApplication
    @SpringBootApplication
    @EnableDiscoveryClient
    public class Tulingvip08MsCloudGatewayApplication {
        public static void main(String[] args) {
            SpringApplication.run(Tulingvip08MsCloudGatewayApplication.class, args);
        }
    }
    
     
    展开全文
  • SpringCloud之服务网关Gateway

    万次阅读 多人点赞 2019-06-30 22:02:38
    Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是Netflix Zuul。网关通常在项目中为了简化 前端的调用逻辑,同时也简化内部服务之间互相调用的复杂度;具体作用就是转发服务,接收并转发所有内外 ...

    前言

      SpringCloud 是微服务中的翘楚,最佳的落地方案。

      Spring Cloud Gateway 是 Spring Cloud 新推出的网关框架,之前是 Netflix Zuul。网关通常在项目中为了简化

      前端的调用逻辑,同时也简化内部服务之间互相调用的复杂度;具体作用就是转发服务,接收并转发所有内外

      部的客户端调用;其他常见的功能还有权限认证,限流控制等等。

      本博客会提到网关的基本转发功能熔断功能限流功能以及功能的综合使用

    源码

      GitHub地址:https://github.com/intomylife/SpringCloud

    环境

    • JDK 1.8.0 +
    • Maven 3.0 +
    • SpringBoot 2.0.3
    • SpringCloud Finchley.RELEASE
    • Redis 3.0 +

    开发工具

    • IntelliJ IDEA

    正文

    commons 工程

    commons 工程 - POM 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <!-- 三坐标 -->
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-commons</artifactId>
        <version>1.0</version>
    
        <!-- 工程名称和描述 -->
        <name>springcloud-gateway-commons</name>
        <description>公用工程</description>
    
        <!-- 打包方式 -->
        <packaging>jar</packaging>
    
        <!-- 在 properties 下声明相应的版本信息,然后在 dependency 下引用的时候用 ${} 就可以引入该版本 jar 包了 -->
        <properties>
            <!-- 编码 -->
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <!-- jdk -->
            <java.version>1.8</java.version>
    
            <!-- SpringBoot -->
            <platform-bom.version>Cairo-SR3</platform-bom.version>
    
            <!-- SpringCloud -->
            <spring-cloud-dependencies.version>Finchley.RELEASE</spring-cloud-dependencies.version>
        </properties>
    
        <!-- 加入依赖 -->
        <dependencies>
    
        </dependencies>
    
        <!-- 依赖 jar 包版本管理的管理器 -->
        <!-- 如果 dependencies 里的 dependency 自己没有声明 version 元素,那么 maven 就此处来找版本声明。 -->
        <!-- 如果有,就会继承它;如果没有就会报错,告诉你没有版本信息 -->
        <!-- 优先级:如果 dependencies 里的 dependency 已经声明了版本信息,就不会生效此处的版本信息了 -->
        <dependencyManagement>
            <dependencies>
                <!-- SpringBoot -->
                <dependency>
                    <groupId>io.spring.platform</groupId>
                    <artifactId>platform-bom</artifactId>
                    <version>${platform-bom.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <!-- SpringCloud -->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud-dependencies.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <!-- 插件依赖 -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • 配置一些共用依赖

    commons 工程 - 项目结构

     

    service 工程

      ① 此工程下有四个模块:一个注册中心,一个网关以及两个提供者

      ② 两个提供者除端口不一致以外,其他代码基本一致

     

    registry-service(注册中心)

    registry-service - POM 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <!-- 继承父 -->
        <parent>
            <groupId>com.zwc</groupId>
            <artifactId>springcloud-gateway-service</artifactId>
            <version>1.0</version>
        </parent>
    
        <!-- 三坐标 -->
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-registry-service</artifactId>
        <version>1.0</version>
    
        <!-- 工程名称描述 -->
        <name>springcloud-gateway-registry-service</name>
        <description>注册中心</description>
    
        <!-- 打包方式 -->
        <packaging>jar</packaging>
    
        <!-- 在 properties下声明相应的版本信息,然后在dependency下引用的时候用 ${} 就可以引入该版本jar包了 -->
        <properties>
    
        </properties>
    
        <!-- 加入依赖 -->
        <dependencies>
            <!-- 服务注册中心 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
        </dependencies>
    
        <!-- 插件依赖 -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • 主要加入 spring-cloud-starter-netflix-eureka-server 依赖

    registry-service - application.yml 配置文件

    # 端口
    server:
      port: 8761
    
    # 应用名称
    spring:
      application:
        name: eureka-server
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        # 是否向注册中心注册自己
        registerWithEureka: false
        # 是否向注册中心获取注册信息
        fetchRegistry: false
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    • 这里使用了默认的 8761 端口,当然也可以更改,不过在发现调用服务端的注册中心地址端口要与它一致

    registry-service - 启动类

    package com.zwc;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    
    @SpringBootApplication
    @EnableEurekaServer
    public class SpringcloudGatewayRegistryServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringcloudGatewayRegistryServiceApplication.class, args);
        }
    
    }
    
    • 在启动类中添加 @EnableEurekaServer 注解表示此工程是注册中心

    registry-service - 启动项目

      1. 项目启动成功后访问 http://localhost:8761/ 即可看到 eureka-server 主页面

     

      注:由于服务工程 A 和服务工程 B 除端口不一致以外,其他代码基本一致,所以服务工程 B 不再赘述

    a-service(服务工程 A)

    a-service - POM 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <!-- 继承父 -->
        <parent>
            <groupId>com.zwc</groupId>
            <artifactId>springcloud-gateway-a-service</artifactId>
            <version>1.0</version>
        </parent>
    
        <!-- 三坐标 -->
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-a-service-core</artifactId>
        <version>1.0</version>
    
        <!-- 工程名称描述 -->
        <name>springcloud-gateway-a-service-core</name>
        <description>服务工程 - A 核心</description>
    
        <!-- 打包方式 -->
        <packaging>jar</packaging>
    
        <!-- 在 properties下声明相应的版本信息,然后在dependency下引用的时候用 ${} 就可以引入该版本jar包了 -->
        <properties>
    
        </properties>
    
        <!-- 加入依赖 -->
        <dependencies>
            <!-- commons工程 依赖 -->
            <dependency>
                <groupId>com.zwc</groupId>
                <artifactId>springcloud-gateway-commons</artifactId>
                <version>1.0</version>
            </dependency>
    
            <!-- api工程 依赖 -->
            <dependency>
                <groupId>com.zwc</groupId>
                <artifactId>springcloud-gateway-a-service-api</artifactId>
                <version>1.0</version>
            </dependency>
    
            <!-- springboot web 依赖 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!-- 提供者消费者 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
        </dependencies>
    
        <!-- 插件依赖 -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • 加入 spring-cloud-starter-netflix-eureka-client 依赖

    a-service - application.yml 配置文件

    # 端口
    server:
      port: 9000
    
    # 应用名称
    spring:
      application:
        name: gateway-service
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    • 注意此处配置注册中心地址的端口为 8761 也就是上面注册中心工程配置的端口

    a-service - controller 前端控制器(提供服务)

    package com.zwc.a.controller;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /*
     * @ClassName ASayHelloController
     * @Desc TODO   Say Hello
     * @Date 2019/5/20 23:24
     * @Version 1.0
     */
    @RestController
    public class ASayHelloController {
    
        /*
         * @ClassName ASayHelloController
         * @Desc TODO   读取配置文件中的端口
         * @Date 2019/5/20 23:24
         * @Version 1.0
         */
        @Value("${server.port}")
        private String port;
    
        /*
         * @ClassName ASayHelloController
         * @Desc TODO   Say Hello
         * @Date 2019/5/20 23:24
         * @Version 1.0
         */
        @RequestMapping("/hello")
        public String hello(){
            return "Hello!I'm a. port:" + port;
        }
    
        /*
         * @ClassName ASayHelloController
         * @Desc TODO   接收从网关传入的参数
         * @Date 2019/6/23 16:28
         * @Version 1.0
         */
        @RequestMapping("/name")
        public String name(String name){
            return "My name is " + name + ". aaa";
        }
    
        /*
         * @ClassName ASayHelloController
         * @Desc TODO   接收从网关传入的参数
         * @Date 2019/6/23 16:52
         * @Version 1.0
         */
        @RequestMapping("/age")
        public String age(String age){
            return "I am " + age + " years old this year. aaa";
        }
    
        /*
         * @ClassName ASayHelloController
         * @Desc TODO   接收从网关传入的参数
         * @Date 2019/6/29 22:00
         * @Version 1.0
         */
        @RequestMapping("/routeAll")
        public String routeAll(String pass) {
            return "Can I pass? " + pass + "! port:" + port;
        }
    
    }
    
    • 提供输出字符串服务,供网关调用

    a-service - 启动类

    package com.zwc;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
    
    @SpringBootApplication
    @EnableEurekaClient
    public class SpringcloudGatewayAServiceCoreApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(SpringcloudGatewayAServiceCoreApplication.class, args);
        }
    
    }
    
    • 添加 @EnableEurekaClient 注解表示此工程可以向注册中心提供服务

    a-service - 启动项目

      1. 刷新 http://localhost:8761/(注册中心)可以看到服务已经被注册进来了

      2. 项目启动成功后访问:http://localhost:9000/hello

      3. 输出内容:'Hello!I'm a. port:9000'

      4. 同样启动服务工程 B后,刷新 http://localhost:8761/(注册中心)

      5. 项目启动成功后访问:http://localhost:9001/hello

      6. 输出内容:'Hello!I'm b. port:9001'

      7. 其他接口是下面网关服务启动后转发调用的,也是本博客的重头戏

     

    master-service(网关)

    master-service - POM 文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <!-- 继承父 -->
        <parent>
            <groupId>com.zwc</groupId>
            <artifactId>springcloud-gateway-service</artifactId>
            <version>1.0</version>
        </parent>
    
        <!-- 三坐标 -->
        <groupId>com.zwc</groupId>
        <artifactId>springcloud-gateway-master-service</artifactId>
        <version>1.0</version>
    
        <!-- 工程名称描述 -->
        <name>springcloud-gateway-master-service</name>
        <description>Spring Cloud Gateway 服务网关</description>
    
        <!-- 打包方式 -->
        <packaging>jar</packaging>
    
        <!-- 在 properties下声明相应的版本信息,然后在 dependency 下引用的时候用 ${} 就可以引入该版本 jar 包了 -->
        <properties>
            <!-- ali json -->
            <fastjson.version>1.2.47</fastjson.version>
        </properties>
    
        <!-- 加入依赖 -->
        <dependencies>
            <!-- 提供者消费者 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
    
            <!-- gateway -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
    
            <!-- redis -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
            </dependency>
    
            <!-- hystrix -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            </dependency>
    
            <!-- ali json依赖 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
        </dependencies>
    
        <!-- 插件依赖 -->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    • 加入 spring-cloud-starter-netflix-eureka-client 依赖:提供和注册服务
    • 加入 spring-cloud-starter-gateway 依赖:gateway
    • 加入 spring-boot-starter-data-redis-reactive 依赖:结合 Redis 限流
    • 加入 spring-cloud-starter-netflix-hystrix 依赖:熔断器

    master-service - application.yml 配置文件

    # 端口
    server:
      port: 8000
    
    spring:
      profiles:
        # 指定配置
        # route_simple:简单尝试
        # route_stripPrefix:截取请求
        # route_uri:转发指定地址并传入参数
        # route_addRequestParameter:转发指定服务并传入参数
        # route_hystrix:熔断
        # route_requestRateLimiter:限流
        # route_all:综合
        active: route_simple
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 简单尝试
      profiles: route_simple
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   简单尝试
          - id: route_simple
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: https://www.zouwencong.com
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 转发地址格式为 uri/archive
            - Path=/archive
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 截取请求
      profiles: route_stripPrefix
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   截取请求
          - id: route_simple
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: https://www.zouwencong.com
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 转发地址格式为 uri/archive,/str 部分会被下面的过滤器给截取掉
            - Path=/str/archive
            filters:
            ## 截取路径位数
            - StripPrefix=1
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 转发指定地址并传入参数
      profiles: route_uri
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   转发指定地址并传入参数
          - id: route_uri
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: http://localhost:9000
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=name, zwc
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 转发指定服务并传入参数
      profiles: route_addRequestParameter
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   转发指定服务并传入参数
          - id: route_addRequestParameter
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=age, three
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 熔断
      profiles: route_hystrix
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   熔断
          - id: route_hystrix
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=age, three
            ## 熔断
            - name: Hystrix
              args:
                name: fallbackcmd
                ### fallback 时调用的方法 http://localhost:8000/fallback
                fallbackUri: forward:/fallback
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 限流
      profiles: route_requestRateLimiter
      redis:
        host: localhost
        port: 6379
        database: 0
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   限流
          - id: route_requestRateLimiter
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=age, three
            ## 限流
            - name: RequestRateLimiter
              args:
                ### 限流过滤器的 Bean 名称
                key-resolver: '#{@uriKeyResolver}'
                ### 希望允许用户每秒处理多少个请求
                redis-rate-limiter.replenishRate: 1
                ### 用户允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 3
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    
    ---
    
    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 综合
      profiles: route_all
      redis:
        host: localhost
        port: 6379
        database: 0
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   综合
          - id: route_all
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 转发地址格式为 uri/routeAll,/all 部分会被下面的过滤器给截取掉
            - Path=/all/routeAll
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 截取路径位数
            - StripPrefix=1
            ## 添加指定参数
            - AddRequestParameter=pass, yes
            ## 熔断
            - name: Hystrix
              args:
                name: fallbackcmd
                ### fallback 时调用的方法 http://localhost:8000/fallback
                fallbackUri: forward:/fallback
            ## 限流
            - name: RequestRateLimiter
              args:
                ### 限流过滤器的 Bean 名称
                key-resolver: '#{@uriKeyResolver}'
                ### 希望允许用户每秒处理多少个请求
                redis-rate-limiter.replenishRate: 1
                ### 用户允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 3
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    • 注意配置注册中心地址的端口都为 8761 也就是上面注册中心工程配置的端口
    • 每一对 '---' 符号中的配置文件都是单独的,使用 spring.profiles.active 指定
    • 每一对 '---' 符号中的配置文件都只配置了一个 route(路由)
    • route(路由)由四部分组成,其中 filters 不是必须参数
    • 唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)

     

    master-service - 简单尝试

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 简单尝试
      profiles: route_simple
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   简单尝试
          - id: route_simple
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: https://www.zouwencong.com
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 转发地址格式为 uri/archive
            - Path=/archive

      1. 停止注册中心工程(registry-service)、服务工程 A 和服务工程 B

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值更改为 route_simple

      3. 上面配置文件内容意思是当访问 http://localhost:8000/archive (网关地址/archive)

          会被转发到 https://www.zouwencong.com/archive/ (uri/archive)

      4. 启动注册中心工程(registry-service)和网关工程(master-service)

      5. 项目启动成功后访问:http://localhost:8000/archive

      6. 发现页面会自动被跳转到:https://www.zouwencong.com/archive/

      7. 证明服务转发成功

     

    master-service - 截取请求

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 截取请求
      profiles: route_stripPrefix
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   截取请求
          - id: route_simple
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: https://www.zouwencong.com
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 转发地址格式为 uri/archive,/str 部分会被下面的过滤器给截取掉
            - Path=/str/archive
            filters:
            ## 截取路径位数
            - StripPrefix=1
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug
    

      1. 停止注册中心工程(registry-service)和网关工程(master-service)

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值更改为 route_stripPrefix

      3. 上面配置文件内容意思是访问的路径 http://localhost:8000/str/archive (网关地址/str/archive)截取 /str 部分,

          截取后被转发到 https://www.zouwencong.com/archive/ (uri/archive)

      4. 启动注册中心工程(registry-service)和网关工程(master-service)

      5. 项目启动成功后访问:http://localhost:8000/str/archive

      6. 发现页面会自动被跳转到:https://www.zouwencong.com/archive/

      7. 证明路径被截取并服务转发成功

     

    master-service - 转发指定地址并传入参数

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 转发指定地址并传入参数
      profiles: route_uri
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   转发指定地址并传入参数
          - id: route_uri
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: http://localhost:9000
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=name, zwc
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug

      1. 停止注册中心工程(registry-service)和网关工程(master-service)

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值更改为 route_uri

      3. 上面配置文件内容意思是访问的路径 http://localhost:8000/name (网关地址/name)

          会被转发到 http://localhost:9000/name(uri/name),并传入 'name=zwc' 参数(注意为 Get 请求)

      4. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A(a-service)

      5. 项目启动成功后访问:http://localhost:8000/name

      6. 输出内容:'My name is zwc. aaa'(通过网关转发 - 参数有值)

      7. 打开新页面访问:http://localhost:9000/name

      8. 输出内容:'My name is null. aaa'(直接访问 - 参数没有值)

      9. 证明转发指定地址并传入参数成功

     

    master-service - 转发指定服务并传入参数

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 转发指定服务并传入参数
      profiles: route_addRequestParameter
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   转发指定服务并传入参数
          - id: route_addRequestParameter
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=age, three
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug

      1. 停止注册中心工程(registry-service),网关工程(master-service)和服务工程 A(a-service)

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值

          更改为 route_addRequestParameter

      3. 上面配置文件内容意思是访问的路径 http://localhost:8000/age (网关地址/age)

          会被转发到 http://gateway-service/age(uri/age),并传入 'age=three' 参数(注意为 Get 请求)

      4. 注意此处的配置 uri: lb://gateway-service 与之前都有所不同,之前都是指定了明确的转发地址,可以满足

          单个服务转发的需求,但是一般情况都会有多个服务,所以这里是指定的服务名称,格式为:lb://应用注册

          服务名。

      5. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      6. 项目启动成功后访问:http://localhost:8000/age

      7. 这时可能会报错 500.错误信息为 'Unable to find instance for gateway-service'

      8. 这种情况不要慌张,只是服务还没有被注册到注册中心,稍等片刻再访问

      9. 多次访问:http://localhost:8000/age

     10. 轮流输出内容:'I am three years old this year. aaa'  'I am three years old this year. bbb'

     11. 此时还通过网关达到了负载均衡的效果

     12. 证明转发指定服务并传入参数成功

     

    master-service - 熔断

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 熔断
      profiles: route_hystrix
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   熔断
          - id: route_hystrix
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=age, three
            ## 熔断
            - name: Hystrix
              args:
                name: fallbackcmd
                ### fallback 时调用的方法 http://localhost:8000/fallback
                fallbackUri: forward:/fallback
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug

      1. 停止注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值更改为 route_hystrix

      3. 上面配置文件内容意思是访问的路径 http://localhost:8000/age (网关地址/age)

          会被转发到 http://gateway-service/age(uri/age),并传入 'age=three' 参数(注意为 Get 请求)

      4. 注意此处的配置 uri: lb://gateway-service 与之前都有所不同,之前都是指定了明确的转发地址,可以满足

          单个服务转发的需求,但是一般情况都会有多个服务,所以这里是指定的服务名称,格式为:lb://应用注册

          服务名。

      5. 此处还多配置了一个过滤器 '- name: Hystrix'(熔断)

      6. 当请求服务出错时,会调用 fallback,路径为:http://localhost:8000/fallback (网关地址/fallback)

      7. 此时就需要如下前端控制器

    master-service - 熔断 - controller

    package com.zwc.gateway.hystrix;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @ClassName FallbackController
     * @Desc TODO   网关断路器
     * @Date 2019/6/23 19:33
     * @Version 1.0
     */
    @RestController
    public class FallbackController {
    
        /*
         * @ClassName FallbackController
         * @Desc TODO   网关断路器
         * @Date 2019/6/23 19:35
         * @Version 1.0
         */
        @RequestMapping("/fallback")
        public String fallback() {
            return "I'm Spring Cloud Gateway fallback.";
        }
    
    }
    

      8. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      9. 项目启动成功后访问:http://localhost:8000/age

     10. 输出内容:'I'm Spring Cloud Gateway fallback.'

     11. 证明熔断成功

     

    master-service - 限流(重点,解决不生效问题)

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 限流
      profiles: route_requestRateLimiter
      redis:
        host: localhost
        port: 6379
        database: 0
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   限流
          - id: route_requestRateLimiter
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 添加指定参数
            - AddRequestParameter=age, three
            ## 限流
            - name: RequestRateLimiter
              args:
                ### 限流过滤器的 Bean 名称
                key-resolver: '#{@uriKeyResolver}'
                ### 希望允许用户每秒处理多少个请求
                redis-rate-limiter.replenishRate: 1
                ### 用户允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 3
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug

      1. 停止注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值

          更改为 route_requestRateLimiter

      3. 上面配置文件内容意思是访问的路径 http://localhost:8000/age (网关地址/age)

          会被转发到 http://gateway-service/age(uri/age),并传入 'age=three' 参数(注意为 Get 请求)

      4. 注意此处还需要配置 redis 的连接信息

      5. 注意此处是结合 redis 实现的限流,所以 filter 过滤器的 name 必须为 RequestRateLimiter

      6. 并且通过实现 KeyResolver 类来自定义限流策略,如下

    master-service - 限流 - 策略

    package com.zwc.gateway.config.filters;
    
    import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    /**
     * @ClassName UriKeyResolver
     * @Desc TODO   Spring Cloud Gateway 网关限流过滤器
     * @Date 2019/6/23 17:59
     * @Version 1.0
     */
    public class UriKeyResolver implements KeyResolver {
    
        /*
         * @ClassName UriKeyResolver
         * @Desc TODO   根据请求的 uri 限流
         * @Date 2019/6/29 17:25
         * @Version 1.0
         */
        @Override
        public Mono<String> resolve(ServerWebExchange exchange) {
            return Mono.just(exchange.getRequest().getURI().getPath());
        }
    
    }
    

      7. 启动本地 redis(redis-server.exe) 服务

      8. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      9. 项目启动成功后访问:http://localhost:8000/age

     10. 此时限流却无论如何都不生效,原因有如下两点

    ① redis-server 版本过低!我 Windows 本地是 redis-2.4.2 版本的,要用 3 以上的版本!!!

    ② 数据在 redis 中存储的时间只有几秒,所以得使用 monitor 指令来动态的观察!!!

     11. 打开 redis-cli.exe,输入命令 monitor 

     12. 快速刷新地址:http://localhost:8000/age

     13. 页面上会出现 429,redis-cli.exe 中会出现很多数据交互(request_rate_limiter.xxx 开头的 key)

     14. 证明限流成功

     

    master-service - 综合

    spring:
      # 配置文件名称,用来标识不同环境的配置。由 spring.profiles.active 的值来决定使用哪组配置。
      ## 综合
      profiles: route_all
      redis:
        host: localhost
        port: 6379
        database: 0
      application:
        # 应用名称
        name: gateway-master
      cloud:
        gateway:
          discovery:
            locator:
              # 是否和服务注册与发现组件结合,设置为 true 后可以直接使用应用名称调用服务
              enabled: true
          # 路由(routes:路由,它由唯一标识(ID)、目标服务地址(uri)、一组断言(predicates)和一组过滤器组成(filters)。filters 不是必需参数。)
          routes:
          # 路由标识(id:标识,具有唯一性)   综合
          - id: route_all
            # 目标服务地址(uri:地址,请求转发后的地址)
            uri: lb://gateway-service
            # 路由条件(predicates:断言,匹配 HTTP 请求内容)
            predicates:
            ## 转发地址格式为 uri/routeAll,/all 部分会被下面的过滤器给截取掉
            - Path=/all/routeAll
            ## 匹配 GET 请求
            - Method=GET
            # 过滤器(filters:过滤器,过滤规则)
            filters:
            ## 截取路径位数
            - StripPrefix=1
            ## 添加指定参数
            - AddRequestParameter=pass, yes
            ## 熔断
            - name: Hystrix
              args:
                name: fallbackcmd
                ### fallback 时调用的方法 http://localhost:8000/fallback
                fallbackUri: forward:/fallback
            ## 限流
            - name: RequestRateLimiter
              args:
                ### 限流过滤器的 Bean 名称
                key-resolver: '#{@uriKeyResolver}'
                ### 希望允许用户每秒处理多少个请求
                redis-rate-limiter.replenishRate: 1
                ### 用户允许在一秒钟内完成的最大请求数
                redis-rate-limiter.burstCapacity: 3
    
    eureka:
      instance:
        # 使用 ip 代替实例名
        prefer-ip-address: true
        # 实例的主机名
        hostname: ${spring.cloud.client.ip-address}
        # 实例的 ID 规则
        instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
      client:
        serviceUrl:
          # 注册中心地址
          defaultZone: http://${eureka.instance.hostname}:8761/eureka/
    
    logging:
      level:
        # log 级别
        org.springframework.cloud.gateway: debug

      1. 停止注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      2. 把 master-service - application.yml 配置文件中最上面的 spring.profiles.active 的值更改为 route_all

      3. 上面配置文件内容意思是访问的路径 http://localhost:8000/all/routeAll (网关地址/all/routeAll)截取 /all 部分,

          会被转发到 http://gateway-service/routeAll(uri/routeAll),并传入 'pass=yes' 参数(注意为 Get 请求)

      4. 启动注册中心工程(registry-service),网关工程(master-service)和服务工程 A/B(a-service、b-service)

      5. 项目启动成功后访问:http://localhost:8000/all/routeAll

      6. 首先会返回 'I'm Spring Cloud Gateway fallback.',因为服务还未被注册到注册中心

      7. 然后会返回 '{"msg":"缺少凭证","code":-1}',因为配置了全局过滤器,如下

    package com.zwc.gateway.config.filters;
    
    import com.alibaba.fastjson.JSONObject;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    import org.springframework.core.io.buffer.DataBuffer;
    
    import java.net.InetSocketAddress;
    import java.nio.charset.StandardCharsets;
    
    /**
     * @ClassName TokenFilter
     * @Desc TODO   请求认证过滤器
     * @Date 2019/6/29 17:49
     * @Version 1.0
     */
    public class TokenFilter implements GlobalFilter{
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            // 请求对象
            ServerHttpRequest request = exchange.getRequest();
            // 响应对象
            ServerHttpResponse response = exchange.getResponse();
    
            // 只有综合路由才添加这个全局过滤器(routesId:route_all)
            // 如果请求路径中不存在 routeAll 字符串
            if(request.getURI().toString().indexOf("routeAll") == -1){
                System.out.println("filter -> return");
                // 直接跳出
                return chain.filter(exchange);
            }
    
            // 从请求中获取 token 参数
            String token = exchange.getRequest().getQueryParams().getFirst("token");
            // 如果为空,那么将返回 401
            if (token == null || token.isEmpty()) {
    
                // 响应消息内容对象
                JSONObject message = new JSONObject();
                // 响应状态
                message.put("code", -1);
                // 响应内容
                message.put("msg", "缺少凭证");
                // 转换响应消息内容对象为字节
                byte[] bits = message.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = response.bufferFactory().wrap(bits);
                // 设置响应对象状态码 401
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                // 设置响应对象内容并且指定编码,否则在浏览器中会中文乱码
                response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
                // 返回响应对象
                return response.writeWith(Mono.just(buffer));
            }
            // 获取请求地址
            String beforePath = request.getPath().pathWithinApplication().value();
            // 获取响应状态码
            HttpStatus beforeStatusCode = response.getStatusCode();
            System.out.println("响应码:" + beforeStatusCode + ",请求路径:" + beforePath);
            // 请求前
            System.out.println("filter -> before");
            // 如果不为空,就通过
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                // 获取请求地址
                String afterPath = request.getPath().pathWithinApplication().value();
                // 获取响应状态码
                HttpStatus afterStatusCode = response.getStatusCode();
                System.out.println("响应码:" + afterStatusCode + ",请求路径:" + afterPath);
                // 响应后
                System.out.println("filter -> after");
            }));
        }
    
    }
    

      8. 全局过滤器,不需要配置在配置文件中,作用于所有路由;只是这里在处理前做了判断,只有路径中存在

          routeAll 字符串才到后续处理;并且处理分为请求前的处理,和响应后的处理

      9. 此时在地址:http://localhost:8000/all/routeAll 中添加 token 参数

     10. 访问:http://localhost:8000/all/routeAll?token=123

     11. 轮流输出内容:'Can I pass? yes! port:9000' 和 'Can I pass? yes! port:9001'

     12. 观察 gateway 工程的控制台,会有如下内容输出

    响应码:null,请求路径:/routeAll
    filter -> before
    响应码:200,请求路径:/routeAll
    filter -> after

     13. 证明全局过滤器过滤成功

     

    service 工程 - 项目结构

     

    把多工程项目使用 IntelliJ IDEA 打开

    1. 把项目从 GitHub 中下载到你的本地
    2. 打开 IntelliJ IDEA 
    3. 点击 File -> Open
    4. 打开你下载到本地的项目目录
    5. springcloud-gateway -> springcloud-gateway-service(选择打开此工程)
    6. 打开 service 工程后
    7. 再次点击 File -> Project Structrue
    8. 选择 Modules,点击 '+' 符号
    9. 点击 Import  Module
    10. 还是打开你下载到本地的项目目录
    11. springcloud-gateway -> springcloud-gateway-commons -> pom.xml
    12. 点击 OK
    13. 点击 Next,Finish
    14. 点击 Apply,OK

     


     

    希望能够帮助到你

    over

     

     

     

    展开全文
  • Spring Cloud Gateway初体验

    万次阅读 多人点赞 2018-11-06 18:55:37
    https://www.fangzhipeng.com/springcloud/2018/11/06/sc-f-gateway1/ 本文出自方志朋的博客 这篇文章讲述了如何简单地使用Spring Cloud Gateway,来源于Spring Cloud官方案例,地址...

    转载请标明出处:
    http://blog.csdn.net/forezp/article/details/83792388
    本文出自方志朋的博客

    点击获取SpringCloud 、Spring Boot视频

    这篇文章讲述了如何简单地使用Spring Cloud Gateway,来源于Spring Cloud官方案例,地址https://spring.io/guides/gs/gateway 。

    简介

    Spring Cloud Gateway是Spring Cloud官方推出的第二代网关框架,取代Zuul网关。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。本文首先用官方的案例带领大家来体验下Spring Cloud的一些简单的功能,在后续文章我会使用详细的案例和源码解析来详细讲解Spring Cloud Gateway.

    创建工程

    本案例的的源码下载于官方案例,也可以在我的Github上下载。工程使用的Spring Boot版本为2.0.5.RELEASE,Spring Cloud版本为Finchley.SR1。

    新建一个工程,取名为sc-f-gateway-first-sight在工程的pom文件引用工程所需的依赖,包括spring boot和spring cloud,以及gateway的起步依赖spring-cloud-starter-gateway,代码如下:

       <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.5.RELEASE</version>
        </parent>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Finchley.SR1</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
     <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    

    ** 注:详细的pom文件依赖,可以见源码。**

    创建一个简单的路由

    在spring cloud gateway中使用RouteLocator的Bean进行路由转发,将请求进行处理,最后转发到目标的下游服务。在本案例中,会将请求转发到http://httpbin.org:80这个地址上。代码如下:

    
    @SpringBootApplication
    @RestController
    public class Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
        @Bean
        public RouteLocator myRoutes(RouteLocatorBuilder builder) {
           return builder.routes()
            .route(p -> p
                .path("/get")
                .filters(f -> f.addRequestHeader("Hello", "World"))
                .uri("http://httpbin.org:80"))
            .build();
        }
        
        }
    

    在上面的myRoutes方法中,使用了一个RouteLocatorBuilder的bean去创建路由,除了创建路由RouteLocatorBuilder可以让你添加各种predicatesfilters,predicates断言的意思,顾名思义就是根据具体的请求的规则,由具体的route去处理,filters是各种过滤器,用来对请求做各种判断和修改。

    上面创建的route可以让请求“/get”请求都转发到“http://httpbin.org/get”。在route配置上,我们添加了一个filter,该filter会将请求添加一个header,key为hello,value为world。

    启动springboot项目,在浏览器上http://localhost:8080/get,浏览器显示如下:

    {
      "args": {}, 
      "headers": {
        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", 
        "Accept-Encoding": "gzip, deflate, br", 
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", 
        "Cache-Control": "max-age=0", 
        "Connection": "close", 
        "Cookie": "_ga=GA1.1.412536205.1526967566; JSESSIONID.667921df=node01oc1cdl4mcjdx1mku2ef1l440q1.node0; screenResolution=1920x1200", 
        "Forwarded": "proto=http;host=\"localhost:8080\";for=\"0:0:0:0:0:0:0:1:60036\"", 
        "Hello": "World", 
        "Host": "httpbin.org", 
        "Upgrade-Insecure-Requests": "1", 
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36", 
        "X-Forwarded-Host": "localhost:8080"
      }, 
      "origin": "0:0:0:0:0:0:0:1, 210.22.21.66", 
      "url": "http://localhost:8080/get"
    }
    
    

    可见当我们向gateway工程请求“/get”,gateway会将工程的请求转发到“http://httpbin.org/get”,并且在转发之前,加上一个filter,该filter会将请求添加一个header,key为hello,value为world。

    注意HTTPBin展示了请求的header hello和值world。

    使用Hystrix

    在spring cloud gateway中可以使用Hystrix。Hystrix是 spring cloud中一个服务熔断降级的组件,在微服务系统有着十分重要的作用。
    Hystrix是 spring cloud gateway中是以filter的形式使用的,代码如下:

       @Bean
        public RouteLocator myRoutes(RouteLocatorBuilder builder) {
            String httpUri = "http://httpbin.org:80";
            return builder.routes()
                .route(p -> p
                    .path("/get")
                    .filters(f -> f.addRequestHeader("Hello", "World"))
                    .uri(httpUri))
                .route(p -> p
                    .host("*.hystrix.com")
                    .filters(f -> f
                        .hystrix(config -> config
                            .setName("mycmd")
                            .setFallbackUri("forward:/fallback")))
                    .uri(httpUri))
                .build();
        }
    
    

    在上面的代码中,我们使用了另外一个router,该router使用host去断言请求是否进入该路由,当请求的host有“*.hystrix.com”,都会进入该router,该router中有一个hystrix的filter,该filter可以配置名称、和指向性fallback的逻辑的地址,比如本案例中重定向到了“/fallback”。

    现在写的一个“/fallback”的l逻辑:

    
     @RequestMapping("/fallback")
        public Mono<String> fallback() {
            return Mono.just("fallback");
        }
    
    

    Mono是一个Reactive stream,对外输出一个“fallback”字符串。

    使用curl执行以下命令:

     curl --dump-header - --header 'Host: www.hystrix.com' http://localhost:8080/delay/3
    
    

    返回的响应为:

    fallback
    

    可见,带hostwww.hystrix.com的请求执行了hystrix的fallback的逻辑。

    总结

    本文通过官方的一个简单的案例,来讲解了spring cloud gateway的简单用法,在spring cloud gateway中有2个重要的概念predicatesfilters,它们个将会在后续文章讲解。敬请期待。

    源码下载

    https://github.com/forezp/SpringCloudLearning/tree/master/sc-f-gateway-first-sight

    更多阅读

    史上最简单的 SpringCloud 教程汇总

    SpringBoot教程汇总

    Java面试题系列汇总


    扫码关注公众号有惊喜

    (转载本站文章请注明作者和出处 方志朋的博客

    展开全文
  • SpringCloudGateway动态路由(Redis持久化)以及请求到寻找路由的流程 1、路由加载流程简述 /** * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)} * 2、路由加载器...

    SpringCloudGateway动态路由(Redis持久化)以及请求到寻找路由的流程

    1、路由加载流程简述

    /**
         * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         * 2、路由加载器获取路由 {@link RouteLocator#getRoutes()} ;{@link RouteLocator}注入到Spring容器的是统一入口{@link CachingRouteLocator},
         *    {@link CompositeRouteLocator#getRoutes()} 在 {@link GatewayAutoConfiguration#cachedCompositeRouteLocator(List)} 注入到Spring容器中,
         * 3、路由定义信息加载器 方法cachedCompositeRouteLocator 中 List<RouteLocator> routeLocators 中,
         *    其中之一{@link RouteDefinitionRouteLocator}
         *    在{@link GatewayAutoConfiguration#routeDefinitionRouteLocator(GatewayProperties, List, List,RouteDefinitionLocator, ConfigurationService)} 注入到Spring容器中,
         *    其中 {@link RouteDefinitionLocator}(路由定义信息加载器)是统一入口 {@link CompositeRouteDefinitionLocator} 在{@link GatewayAutoConfiguration#routeDefinitionLocator(List)}注入到Spring容器中,
         *    其中 List<RouteDefinitionLocator> routeDefinitionLocators 包含
         *    读取配置文件的 {@link GatewayAutoConfiguration#propertiesRouteDefinitionLocator(GatewayProperties)}
         *    不存在持久化bean的时候 {@link GatewayAutoConfiguration#inMemoryRouteDefinitionRepository()}
         * 4、加载路由定义信息 {@link RouteDefinitionLocator#getRouteDefinitions()} {@link CompositeRouteDefinitionLocator#getRouteDefinitions()} 会统一加载,所有的 RouteDefinitionLocator bean
         *
         * 流程如下 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         *  {@link RouteLocator#getRoutes()} --[{@link CompositeRouteLocator#getRoutes()} {@link CachingRouteLocator#getRoutes()} 主要
         *  {@link RouteDefinitionRouteLocator#getRoutes()},初始化过滤器、断言等都在此类 ]
         *  {@link RouteDefinitionRouteLocator} 中的{@link RouteDefinitionLocator#getRouteDefinitions()}获取路由信息,{@link RouteDefinitionRouteLocator#convertToRoute(RouteDefinition)}
         *  路由信息转换为路由
         *
         *  RoutePredicateHandlerMapping 对应的映射,访问一次都会加载一次
         * @return
         */
    

    2、动态路由,redis存储

    • Controller
    @RestController
    public class GatewayRouteController extends GatewayBaseController{
    
        @Autowired
        DynamicRouteService routeService;
        @Autowired
        GatewayAppRouteRedisRepository redisRepository;
    
    //    @PostMapping(value = "add", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    //    public Response save(@RequestBody GatewayRouteDefinition definition) {
    //        routeService.save(definition);
    //        return Response.success();
    //    }
    
        @PostMapping("route/save_or_update")
        public Mono<RestResult> update(@RequestBody GatewayAppRoute definition) {
            routeService.update(definition);
            redisRepository.update(definition);
            return Mono.just(TRestBuilder.success());
        }
    
    
        @DeleteMapping("route/{id}")
        public Mono<RestResult> delete(@PathVariable("id") String id) {
            routeService.delete(id);
            redisRepository.delete(id);
            return Mono.just(TRestBuilder.success());
        }
    
        @PostMapping("routes")
        public Mono<RestResult<List<GatewayAppRoute>>> list() {
            return Mono.just(TRestBuilder.success(redisRepository.routeViews()));
        }
    }
    
    • 动态路由
    /**
     * 动态路由信息
     */
    public class DynamicRouteService implements ApplicationEventPublisherAware {
        @Autowired
        RouteDefinitionRepository routeDefinitionRepository;// 实现redis存储
    
        private ApplicationEventPublisher publisher;
        @Override
        public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
         this.publisher=applicationEventPublisher;
        }
    
        // 发布事件,刷新路由,实现动态路由
        private void publish() {
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
        }
    
        public void save(GatewayAppRoute definition){
            RouteDefinition routeDefinition=definition.routeDefinition();
            routeDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
            publish();
        }
    
    
        public void update(GatewayAppRoute definition){
            RouteDefinition routeDefinition=definition.routeDefinition();
            routeDefinitionRepository.delete(Mono.just(definition.getServiceId()));
            routeDefinitionRepository.save(Mono.just(routeDefinition)).subscribe();
            publish();
        }
    
    
        public void delete(String serviceId){
            routeDefinitionRepository.delete(Mono.just(serviceId));
            publish();
        }
    }
    
    • Redis持久化
    /**
     * 路由存储 redis
     */
    public class RouteDefinitionRedisRepository implements RouteDefinitionRepository,RouteRepository {
        final static String GATEWAY_ROUTES = "GATEWAY:ROUTE";
        @Autowired
        RedisCache redisCache;//redis操作,Redistemplate
    
        /**
         * 从redis加在路由信息
         * @return
         */
        public Map<String,RouteDefinition> loadRoute() {
            Map<String, RouteDefinition> data = redisCache.getCacheMap(GATEWAY_ROUTES, RouteDefinition.class);
            return data;
        }
    
        /**
         * 1、处理映射器加载路由 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         * 2、路由加载器获取路由 {@link RouteLocator#getRoutes()} ;{@link RouteLocator}注入到Spring容器的是统一入口{@link CachingRouteLocator},
         *    {@link CompositeRouteLocator#getRoutes()} 在 {@link GatewayAutoConfiguration#cachedCompositeRouteLocator(List)} 注入到Spring容器中,
         * 3、路由定义信息加载器 方法cachedCompositeRouteLocator 中 List<RouteLocator> routeLocators 中,
         *    其中之一{@link RouteDefinitionRouteLocator}
         *    在{@link GatewayAutoConfiguration#routeDefinitionRouteLocator(GatewayProperties, List, List,RouteDefinitionLocator, ConfigurationService)} 注入到Spring容器中,
         *    其中 {@link RouteDefinitionLocator}(路由定义信息加载器)是统一入口 {@link CompositeRouteDefinitionLocator} 在{@link GatewayAutoConfiguration#routeDefinitionLocator(List)}注入到Spring容器中,
         *    其中 List<RouteDefinitionLocator> routeDefinitionLocators 包含
         *    读取配置文件的 {@link GatewayAutoConfiguration#propertiesRouteDefinitionLocator(GatewayProperties)}
         *    不存在持久化bean的时候 {@link GatewayAutoConfiguration#inMemoryRouteDefinitionRepository()}
         * 4、加载路由定义信息 {@link RouteDefinitionLocator#getRouteDefinitions()} {@link CompositeRouteDefinitionLocator#getRouteDefinitions()} 会统一加载,所有的 RouteDefinitionLocator bean
         *
         * 流程如下 {@link RoutePredicateHandlerMapping#lookupRoute(ServerWebExchange)}
         *  {@link RouteLocator#getRoutes()} --[{@link CompositeRouteLocator#getRoutes()} {@link CachingRouteLocator#getRoutes()} 主要
         *  {@link RouteDefinitionRouteLocator#getRoutes()},初始化过滤器、断言等都在此类 ]
         *  {@link RouteDefinitionRouteLocator} 中的{@link RouteDefinitionLocator#getRouteDefinitions()}获取路由信息,{@link RouteDefinitionRouteLocator#convertToRoute(RouteDefinition)}
         *  路由信息转换为路由
         *
         *  RoutePredicateHandlerMapping 对应的映射,访问一次都会加载一次
         * @return
         */
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
            List<RouteDefinition> routeDefinitions = new ArrayList<>();
            Map<String, RouteDefinition> data = loadRoute();
            if (!CollectionUtils.isEmpty(data)) {
                data.forEach((K, V) -> routeDefinitions.add(V));
            }
            return Flux.fromIterable(routeDefinitions);
        }
    
        @Override
        public Mono<Void> save(Mono<RouteDefinition> route) {
            return route.flatMap(routeDefinition -> {
                redisCache.putDataToCacheMap(GATEWAY_ROUTES, routeDefinition.getId(), routeDefinition);
                return Mono.empty();
            });
        }
    
        @Override
        public Mono<Void> delete(Mono<String> routeId) {
            return routeId.flatMap(id -> {
                if (redisCache.cacheMapHasKey(GATEWAY_ROUTES, id)) {
                    redisCache.deleteDataFromCacheMap(GATEWAY_ROUTES, id);
                    return Mono.empty();
                }
                return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: " + routeId)));
            });
        }
    
        @Override
        public List<RouteDefinition> loadRoutes() {
            Map<String,RouteDefinition> data=loadRoute();
            return CollectionUtils.isEmpty(data)?new ArrayList<>():new ArrayList<>(data.values());
        }
    }
    
    
    • GatewayAppRoute
    /**
     * APP 配置信息
     */
    @Data
    public class GatewayAppRoute {
        /**
         * 服务状态
         */
        private int serviceStatus;
        /**
         * 服务名称
         */
        @NotBlank(message = "serviceName不能为空")
        private String serviceName;
        /**
         * 服务版本号
         */
        @NotBlank(message = "serviceVersion不能为空")
        private String serviceVersion;
        /**
         * 路由ID(服务ID)
         */
        @NotBlank(message = "serviceId不能为空")
        private String serviceId;
        /**
         * 路由断言集合配置
         */
        @NotEmpty(message = "predicates不能为空")
        private List<GatewayDefinition> predicates = new ArrayList<>();
        /**
         * 路由过滤器集合配置
         */
        private List<GatewayDefinition> filters = new ArrayList<>();
        /**
         * 路由规则转发的目标uri
         *
         * 建议lb协议<lb://serviceId>
         */
        @NotBlank(message = "uri不能为空")
        private String uri;
        /**
         * 路由执行顺序
         */
        private int order = 0;
    
        @Data
        public static class GatewayDefinition {
            //断言(过滤器)对应的Name
            private String name;
            //配置的断言(过滤器)规则
            private Map<String,String> args=new LinkedHashMap<>();
        }
    
        public RouteDefinition routeDefinition(){
            RouteDefinition routeDefinition=new RouteDefinition();
            routeDefinition.setId(serviceId);
            routeDefinition.setOrder(order);
            URI routeUri = !StringUtils.startsWith(uri,"lb")?UriComponentsBuilder.fromHttpUrl(uri).build().toUri():URI.create(uri);
            routeDefinition.setUri(routeUri);
            if(!CollectionUtils.isEmpty(filters)){
                routeDefinition.setFilters(filters.stream().map(f->{
                    FilterDefinition filterDefinition=new FilterDefinition();
                    filterDefinition.setName(f.name);
                    filterDefinition.setArgs(f.args);
                    return filterDefinition;
                }).collect(Collectors.toList()));
            }
            if(!CollectionUtils.isEmpty(predicates)){
                routeDefinition.setPredicates(predicates.stream().map(f->{
                    PredicateDefinition predicateDefinition=new PredicateDefinition();
                    predicateDefinition.setName(f.name);
                    predicateDefinition.setArgs(f.args);
                    return predicateDefinition;
                }).collect(Collectors.toList()));
            }
            return routeDefinition;
        }
    }
    

    3. SpringCloudGateway 请求到寻找路由的流程

    DispatcherHandler
    package org.springframework.web.reactive;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;
    
    import org.springframework.beans.factory.BeanFactoryUtils;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    import org.springframework.http.HttpStatus;
    import org.springframework.lang.Nullable;
    import org.springframework.web.server.ResponseStatusException;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.web.server.WebHandler;
    import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
    
    /**
     * Central dispatcher for HTTP request handlers/controllers. Dispatches to
     * registered handlers for processing a request, providing convenient mapping
     * facilities.
     *
     * <p>{@code DispatcherHandler} discovers the delegate components it needs from
     * Spring configuration. It detects the following in the application context:
     * <ul>
     * <li>{@link HandlerMapping} -- map requests to handler objects
     * <li>{@link HandlerAdapter} -- for using any handler interface
     * <li>{@link HandlerResultHandler} -- process handler return values
     * </ul>
     *
     * <p>{@code DispatcherHandler} is also designed to be a Spring bean itself and
     * implements {@link ApplicationContextAware} for access to the context it runs
     * in. If {@code DispatcherHandler} is declared with the bean name "webHandler"
     * it is discovered by {@link WebHttpHandlerBuilder#applicationContext} which
     * creates a processing chain together with {@code WebFilter},
     * {@code WebExceptionHandler} and others.
     *
     * <p>A {@code DispatcherHandler} bean declaration is included in
     * {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux}
     * configuration.
     *
     * @author Rossen Stoyanchev
     * @author Sebastien Deleuze
     * @author Juergen Hoeller
     * @since 5.0
     * @see WebHttpHandlerBuilder#applicationContext(ApplicationContext)
     */
    public class DispatcherHandler implements WebHandler, ApplicationContextAware {
    
    	@Nullable
    	private List<HandlerMapping> handlerMappings;
    
    	@Nullable
    	private List<HandlerAdapter> handlerAdapters;
    
    	@Nullable
    	private List<HandlerResultHandler> resultHandlers;
    
    
    	/**
    	 * Create a new {@code DispatcherHandler} which needs to be configured with
    	 * an {@link ApplicationContext} through {@link #setApplicationContext}.
    	 */
    	public DispatcherHandler() {
    	}
    
    	/**
    	 * Create a new {@code DispatcherHandler} for the given {@link ApplicationContext}.
    	 * @param applicationContext the application context to find the handler beans in
    	 */
    	public DispatcherHandler(ApplicationContext applicationContext) {
    		initStrategies(applicationContext);
    	}
    
    
    	/**
    	 * Return all {@link HandlerMapping} beans detected by type in the
    	 * {@link #setApplicationContext injected context} and also
    	 * {@link AnnotationAwareOrderComparator#sort(List) sorted}.
    	 * <p><strong>Note:</strong> This method may return {@code null} if invoked
    	 * prior to {@link #setApplicationContext(ApplicationContext)}.
    	 * @return immutable list with the configured mappings or {@code null}
    	 */
    	@Nullable
    	public final List<HandlerMapping> getHandlerMappings() {
    		return this.handlerMappings;
    	}
    
    	@Override
    	public void setApplicationContext(ApplicationContext applicationContext) {
    		initStrategies(applicationContext);
    	}
    
        // 初始化处理
    	protected void initStrategies(ApplicationContext context) {
    		Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    				context, HandlerMapping.class, true, false);
    
    		ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
    		AnnotationAwareOrderComparator.sort(mappings);
    		this.handlerMappings = Collections.unmodifiableList(mappings);
    
    		Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    				context, HandlerAdapter.class, true, false);
    
    		this.handlerAdapters = new ArrayList<>(adapterBeans.values());
    		AnnotationAwareOrderComparator.sort(this.handlerAdapters);
    
    		Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
    				context, HandlerResultHandler.class, true, false);
    
    		this.resultHandlers = new ArrayList<>(beans.values());
    		AnnotationAwareOrderComparator.sort(this.resultHandlers);
    	}
    
    
        // 获取映射处理器
    	@Override
    	public Mono<Void> handle(ServerWebExchange exchange) {
    		if (this.handlerMappings == null) {
    			return createNotFoundError();
    		}
    		return Flux.fromIterable(this.handlerMappings)
                     // 获取处理器,与已经注册好了的HandlerAdapter一一匹配
                     // org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
                     //AbstractHandlerMapping 有多个子类,子类都会进入父类getHandler 
    				.concatMap(mapping -> mapping.getHandler(exchange))
    				.next()
    				.switchIfEmpty(createNotFoundError())
                      // 执行
    				.flatMap(handler -> invokeHandler(exchange, handler))
                      // 结果处理
    				.flatMap(result -> handleResult(exchange, result));
    	}
    
    	private <R> Mono<R> createNotFoundError() {
    		return Mono.defer(() -> {
    			Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler");
    			return Mono.error(ex);
    		});
    	}
        // 看哪一种HandlerAdapter是支持该controller类型的
    	private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
    		if (this.handlerAdapters != null) {
    			for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
    				if (handlerAdapter.supports(handler)) {
    					return handlerAdapter.handle(exchange, handler);
    				}
    			}
    		}
    		return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
    	}
    
    	private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
    		return getResultHandler(result).handleResult(exchange, result)
    				.checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
    				.onErrorResume(ex ->
    						result.applyExceptionHandler(ex).flatMap(exResult -> {
    							String text = "Exception handler " + exResult.getHandler() +
    									", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
    							return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
    						}));
    	}
    
    	private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
    		if (this.resultHandlers != null) {
    			for (HandlerResultHandler resultHandler : this.resultHandlers) {
    				if (resultHandler.supports(handlerResult)) {
    					return resultHandler;
    				}
    			}
    		}
    		throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
    	}
    
    }
    
    

    其中 org.springframework.web.reactive.DispatcherHandler#handle(ServerWebExchange exchange)

    根据请求从handlerMappings获取对应的处理器映射,通过处理器映射,可以将web请求映射到正确的处理器(handler)上。

    @Override
    	public Mono<Object> getHandler(ServerWebExchange exchange) {
    		return getHandlerInternal(exchange).map(handler -> {
    			if (logger.isDebugEnabled()) {
    				logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
    			}
    			ServerHttpRequest request = exchange.getRequest();
    			if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
    				CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
    				CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
    				config = (config != null ? config.combine(handlerConfig) : handlerConfig);
    				if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
    					return REQUEST_HANDLED_HANDLER;
    				}
    			}
    			return handler;
    		});
    	}
    /**
    	 * Look up a handler for the given request, returning an empty {@code Mono}
    	 * if no specific one is found. This method is called by {@link #getHandler}.
    	 * <p>On CORS pre-flight requests this method should return a match not for
    	 * the pre-flight request but for the expected actual request based on the URL
    	 * path, the HTTP methods from the "Access-Control-Request-Method" header, and
    	 * the headers from the "Access-Control-Request-Headers" header.
    	 * @param exchange current exchange
    	 * @return {@code Mono} for the matching handler, if any
    	 */
    	protected abstract Mono<?> getHandlerInternal(ServerWebExchange exchange);
    

    在这里插入图片描述

    这里,看到了gateway的RoutePredicateHandlerMapping

    org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping

    RoutePredicateHandlerMapping

    org.springframework.cloud.gateway.config.GatewayAutoConfiguration 初始化

    package org.springframework.cloud.gateway.handler;
    
    import java.util.function.Function;
    
    import reactor.core.publisher.Mono;
    
    import org.springframework.cloud.gateway.config.GlobalCorsProperties;
    import org.springframework.cloud.gateway.route.Route;
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.core.env.Environment;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.reactive.handler.AbstractHandlerMapping;
    import org.springframework.web.server.ServerWebExchange;
    
    import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT;
    import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DISABLED;
    import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.SAME;
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR;
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR;
    import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
    
    /**
     * @author Spencer Gibb
     */
    public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    
       private final FilteringWebHandler webHandler;
       // 路由统一加载的实例(org.springframework.cloud.gateway.route.CompositeRouteLocator)
       // org.springframework.cloud.gateway.route.CachingRouteLocator
       private final RouteLocator routeLocator;
    
       private final Integer managementPort;
    
       private final ManagementPortType managementPortType;
    
       public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
             RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
             Environment environment) {
          this.webHandler = webHandler;
          this.routeLocator = routeLocator;
    
          this.managementPort = getPortProperty(environment, "management.server.");
          this.managementPortType = getManagementPortType(environment);
          setOrder(1);
          setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
       }
    
       private ManagementPortType getManagementPortType(Environment environment) {
          Integer serverPort = getPortProperty(environment, "server.");
          if (this.managementPort != null && this.managementPort < 0) {
             return DISABLED;
          }
          return ((this.managementPort == null
                || (serverPort == null && this.managementPort.equals(8080))
                || (this.managementPort != 0 && this.managementPort.equals(serverPort)))
                      ? SAME : DIFFERENT);
       }
    
       private static Integer getPortProperty(Environment environment, String prefix) {
          return environment.getProperty(prefix + "port", Integer.class);
       }
    
        // 网关路由时进入此方法
       @Override
       protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
          // don't handle requests on management port if set and different than server port
          if (this.managementPortType == DIFFERENT && this.managementPort != null
                && exchange.getRequest().getURI().getPort() == this.managementPort) {
             return Mono.empty();
          }
          exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
    
           // 获取配置路由
          return lookupRoute(exchange)
                // .log("route-predicate-handler-mapping", Level.FINER) //name this
                .flatMap((Function<Route, Mono<?>>) r -> {
                   exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
                   if (logger.isDebugEnabled()) {
                      logger.debug(
                            "Mapping [" + getExchangeDesc(exchange) + "] to " + r);
                   }
    
                   exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
                   return Mono.just(webHandler);
                }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                   exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
                   if (logger.isTraceEnabled()) {
                      logger.trace("No RouteDefinition found for ["
                            + getExchangeDesc(exchange) + "]");
                   }
                })));
       }
    
       @Override
       protected CorsConfiguration getCorsConfiguration(Object handler,
             ServerWebExchange exchange) {
          // TODO: support cors configuration via properties on a route see gh-229
          // see RequestMappingHandlerMapping.initCorsConfiguration()
          // also see
          // https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java
          return super.getCorsConfiguration(handler, exchange);
       }
    
       // TODO: get desc from factory?
       private String getExchangeDesc(ServerWebExchange exchange) {
          StringBuilder out = new StringBuilder();
          out.append("Exchange: ");
          out.append(exchange.getRequest().getMethod());
          out.append(" ");
          out.append(exchange.getRequest().getURI());
          return out.toString();
       }
    
       protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
           // 获取加载路由
          return this.routeLocator.getRoutes()
                // individually filter routes so that filterWhen error delaying is not a
                // problem
                .concatMap(route -> Mono.just(route).filterWhen(r -> {
                   // add the current route we are testing
                   exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                   return r.getPredicate().apply(exchange);
                })
                      // instead of immediately stopping main flux due to error, log and
                      // swallow it
                      .doOnError(e -> logger.error(
                            "Error applying predicate for route: " + route.getId(),
                            e))
                      .onErrorResume(e -> Mono.empty()))
                // .defaultIfEmpty() put a static Route not found
                // or .switchIfEmpty()
                // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
                .next()
                // TODO: error handling
                .map(route -> {
                   if (logger.isDebugEnabled()) {
                      logger.debug("Route matched: " + route.getId());
                   }
                   validateRoute(route, exchange);
                   return route;
                });
    
          /*
           * TODO: trace logging if (logger.isTraceEnabled()) {
           * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
           */
       }
    
       /**
        * Validate the given handler against the current request.
        * <p>
        * The default implementation is empty. Can be overridden in subclasses, for example
        * to enforce specific preconditions expressed in URL mappings.
        * @param route the Route object to validate
        * @param exchange current exchange
        * @throws Exception if validation failed
        */
       @SuppressWarnings("UnusedParameters")
       protected void validateRoute(Route route, ServerWebExchange exchange) {
       }
    
       protected String getSimpleName() {
          return "RoutePredicateHandlerMapping";
       }
    
       public enum ManagementPortType {
    
          /**
           * The management port has been disabled.
           */
          DISABLED,
    
          /**
           * The management port is the same as the server port.
           */
          SAME,
    
          /**
           * The management port and server port are different.
           */
          DIFFERENT;
    
       }
    
    }
    
    RouteLocator路由加载
    package org.springframework.cloud.gateway.route;
    
    import reactor.core.publisher.Flux;
    /** 
     * org.springframework.cloud.gateway.route.CachingRouteLocator 缓存,有事件监听
     * org.springframework.cloud.gateway.route.CompositeRouteLocator 组合多种实现,提供统一入口
     * org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator 将路由定义信息转化为路由
     * @author Spencer Gibb
     */
    // TODO: rename to Routes?
    public interface RouteLocator {
    
       Flux<Route> getRoutes();
    
    }
    

    GatewayAutoConfiguration 加载代码

    @Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
          List<GatewayFilterFactory> gatewayFilters,
          List<RoutePredicateFactory> predicates,
          RouteDefinitionLocator routeDefinitionLocator,
          ConfigurationService configurationService) {
       return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
             gatewayFilters, properties, configurationService);
    }
    
    @Bean
    @Primary
    @ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
    // TODO: property to disable composite?
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
       return new CachingRouteLocator(
             new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }
    
    • RouteDefinitionRouteLocator
    package org.springframework.cloud.gateway.route;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import reactor.core.publisher.Flux;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.config.GatewayProperties;
    import org.springframework.cloud.gateway.event.FilterArgsEvent;
    import org.springframework.cloud.gateway.event.PredicateArgsEvent;
    import org.springframework.cloud.gateway.filter.FilterDefinition;
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
    import org.springframework.cloud.gateway.handler.AsyncPredicate;
    import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
    import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
    import org.springframework.cloud.gateway.support.ConfigurationService;
    import org.springframework.cloud.gateway.support.HasRouteId;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.context.ApplicationEventPublisherAware;
    import org.springframework.core.Ordered;
    import org.springframework.core.annotation.AnnotationAwareOrderComparator;
    import org.springframework.core.convert.ConversionService;
    import org.springframework.validation.Validator;
    import org.springframework.web.server.ServerWebExchange;
    
    /**
     * {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator}.
     *
     * @author Spencer Gibb
     */
    public class RouteDefinitionRouteLocator
    		implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
    
    	/**
    	 * Default filters name.
    	 */
    	public static final String DEFAULT_FILTERS = "defaultFilters";
    
    	protected final Log logger = LogFactory.getLog(getClass());
         // 路由定义信息
    	private final RouteDefinitionLocator routeDefinitionLocator;
    
    	private final ConfigurationService configurationService;
        // 路由RoutePredicate工厂,配置该路由决定采取哪种路由规则,如何配置前缀就可以找到对应的实例??
    	private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
        // 路由GatewayFilter工厂,配置该路由决定走哪些过滤器,如何配置前缀就可以找到对应的实例??
    	private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
    
    	private final GatewayProperties gatewayProperties;
    
    	@Deprecated
    	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
    			List<RoutePredicateFactory> predicates,
    			List<GatewayFilterFactory> gatewayFilterFactories,
    			GatewayProperties gatewayProperties, ConversionService conversionService) {
    		this.routeDefinitionLocator = routeDefinitionLocator;
    		this.configurationService = new ConfigurationService();
    		this.configurationService.setConversionService(conversionService);
    		initFactories(predicates);
    		gatewayFilterFactories.forEach(
    				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
    		this.gatewayProperties = gatewayProperties;
    	}
    
    	public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
    			List<RoutePredicateFactory> predicates,
    			List<GatewayFilterFactory> gatewayFilterFactories,
    			GatewayProperties gatewayProperties,
    			ConfigurationService configurationService) {
    		this.routeDefinitionLocator = routeDefinitionLocator;
    		this.configurationService = configurationService;
            // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
    		initFactories(predicates);
            // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
    		gatewayFilterFactories.forEach(
    				factory -> this.gatewayFilterFactories.put(factory.name(), factory));
    		this.gatewayProperties = gatewayProperties;
    	}
    
    	@Override
    	@Deprecated
    	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    		if (this.configurationService.getBeanFactory() == null) {
    			this.configurationService.setBeanFactory(beanFactory);
    		}
    	}
    
    	@Autowired
    	@Deprecated
    	public void setValidator(Validator validator) {
    		if (this.configurationService.getValidator() == null) {
    			this.configurationService.setValidator(validator);
    		}
    	}
    
    	@Override
    	@Deprecated
    	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
    		if (this.configurationService.getPublisher() == null) {
    			this.configurationService.setApplicationEventPublisher(publisher);
    		}
    	}
    
        // 配置前缀就可以找到对应的实例,将容器中的bean先放到内存
    	private void initFactories(List<RoutePredicateFactory> predicates) {
    		predicates.forEach(factory -> {
    			String key = factory.name();
    			if (this.predicates.containsKey(key)) {
    				this.logger.warn("A RoutePredicateFactory named " + key
    						+ " already exists, class: " + this.predicates.get(key)
    						+ ". It will be overwritten.");
    			}
    			this.predicates.put(key, factory);
    			if (logger.isInfoEnabled()) {
    				logger.info("Loaded RoutePredicateFactory [" + key + "]");
    			}
    		});
    	}
    
    	@Override
    	public Flux<Route> getRoutes() {
            // 将路由定义信息转化成路由信息
    		Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
    				.map(this::convertToRoute);
    
    		if (!gatewayProperties.isFailOnRouteDefinitionError()) {
    			// instead of letting error bubble up, continue
    			routes = routes.onErrorContinue((error, obj) -> {
    				if (logger.isWarnEnabled()) {
    					logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()
    							+ " will be ignored. Definition has invalid configs, "
    							+ error.getMessage());
    				}
    			});
    		}
    
    		return routes.map(route -> {
    			if (logger.isDebugEnabled()) {
    				logger.debug("RouteDefinition matched: " + route.getId());
    			}
    			return route;
    		});
    	}
         
        // 转换成路由信息
    	private Route convertToRoute(RouteDefinition routeDefinition) {
    		AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
    		List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
    
    		return Route.async(routeDefinition).asyncPredicate(predicate)
    				.replaceFilters(gatewayFilters).build();
    	}
    
    	@SuppressWarnings("unchecked")
        // 加载路由网关过滤器
    	List<GatewayFilter> loadGatewayFilters(String id,
    			List<FilterDefinition> filterDefinitions) {
    		ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
    		for (int i = 0; i < filterDefinitions.size(); i++) {
    			FilterDefinition definition = filterDefinitions.get(i);
                // 获取网关过滤器工厂
    			GatewayFilterFactory factory = this.gatewayFilterFactories
    					.get(definition.getName());
    			if (factory == null) {
    				throw new IllegalArgumentException(
    						"Unable to find GatewayFilterFactory with name "
    								+ definition.getName());
    			}
    			if (logger.isDebugEnabled()) {
    				logger.debug("RouteDefinition " + id + " applying filter "
    						+ definition.getArgs() + " to " + definition.getName());
    			}
    
    			// @formatter:off
                // 构造每个工厂里对应的config信息
    			Object configuration = this.configurationService.with(factory)
    					.name(definition.getName())
    					.properties(definition.getArgs())
    					.eventFunction((bound, properties) -> new FilterArgsEvent(
    							// TODO: why explicit cast needed or java compile fails
    							RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
    					.bind();
    			// @formatter:on
    
    			// some filters require routeId
    			// TODO: is there a better place to apply this?
    			if (configuration instanceof HasRouteId) {
    				HasRouteId hasRouteId = (HasRouteId) configuration;
    				hasRouteId.setRouteId(id);
    			}
                 // 获取过滤器是实例
    			GatewayFilter gatewayFilter = factory.apply(configuration);
    			if (gatewayFilter instanceof Ordered) {
    				ordered.add(gatewayFilter);
    			}
    			else {
    				ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
    			}
    		}
    
    		return ordered;
    	}
        // 获取过滤器,并根据ordered决定加载顺序
    	private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
    		List<GatewayFilter> filters = new ArrayList<>();
    
    		// TODO: support option to apply defaults after route specific filters?
    		if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
    			filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
    					new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
    		}
    
    		if (!routeDefinition.getFilters().isEmpty()) {
    			filters.addAll(loadGatewayFilters(routeDefinition.getId(),
    					new ArrayList<>(routeDefinition.getFilters())));
    		}
    
    		AnnotationAwareOrderComparator.sort(filters);
    		return filters;
    	}
    
    	private AsyncPredicate<ServerWebExchange> combinePredicates(
    			RouteDefinition routeDefinition) {
    		List<PredicateDefinition> predicates = routeDefinition.getPredicates();
    		if (predicates == null || predicates.isEmpty()) {
    			// this is a very rare case, but possible, just match all
    			return AsyncPredicate.from(exchange -> true);
    		}
    		AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
    				predicates.get(0));
    
    		for (PredicateDefinition andPredicate : predicates.subList(1,
    				predicates.size())) {
    			AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
    					andPredicate);
    			predicate = predicate.and(found);
    		}
    
    		return predicate;
    	}
        //加载断言
    	@SuppressWarnings("unchecked")
    	private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
    			PredicateDefinition predicate) {
            // 获取断言工厂
    		RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
    		if (factory == null) {
    			throw new IllegalArgumentException(
    					"Unable to find RoutePredicateFactory with name "
    							+ predicate.getName());
    		}
    		if (logger.isDebugEnabled()) {
    			logger.debug("RouteDefinition " + route.getId() + " applying "
    					+ predicate.getArgs() + " to " + predicate.getName());
    		}
    
    		// @formatter:off
    		Object config = this.configurationService.with(factory)
    				.name(predicate.getName())
    				.properties(predicate.getArgs())
    				.eventFunction((bound, properties) -> new PredicateArgsEvent(
    						RouteDefinitionRouteLocator.this, route.getId(), properties))
    				.bind();
    		// @formatter:on
             // 转换实例信息
    		return factory.applyAsync(config);
    	}
    
    }
    
    
    RouteDefinition路由定义

    SpringCloudGateway通过RouteDefinition来转换生成具体的路由信息。RouteDefinition的信息是怎么加载初始化到网关系统中的,主要是通过RouteDefinitionLocator(路由定义信息加载器)接口,实现RouteDefinition初始化加载

    • RouteDefinitionLocator源码
    /**
     * 路由定义信息的定位器,
     * 负责读取路由配置( org.springframework.cloud.gateway.route.RouteDefinition
     * 子类实现类
     *  1.CachingRouteDefinitionLocator -RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
     *  2.CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
     *  3.PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
     *  4.DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取RouteDefinition
     *  5.RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
     * @author Spencer Gibb
     */
    public interface RouteDefinitionLocator {
    
        /**
         * 获取RouteDefinition
         * @return
         */
        Flux<RouteDefinition> getRouteDefinitions();
    }
    

    RouteDefinitionLocator接口有且仅有一个方法getRouteDefinitions,此方法获取RouteDefinition的核心方法,返回Flux

    RouteDefinitionLocator 类图如下:

    graph TD
    RouteDefinitionLocator-->CachingRouteDefinitionLocator
    RouteDefinitionLocator-->CompositeRouteDefinitionLocator
    RouteDefinitionLocator-->PropertiesRouteDefinitionLocator
    RouteDefinitionLocator-->DiscoveryClientRouteDefinitionLocator
    RouteDefinitionLocator-->RouteDefinitionRepository
    

    子类功能描述:

    • CachingRouteDefinitionLocator:RouteDefinitionLocator包装类, 缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能
    • CompositeRouteDefinitionLocator -RouteDefinitionLocator包装类,组合多种 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
    • PropertiesRouteDefinitionLocator-从配置文件(GatewayProperties 例如,YML / Properties 等 ) 读取RouteDefinition
    • RouteDefinitionRepository-从存储器( 例如,内存 / Redis / MySQL 等 )读取RouteDefinition
    • DiscoveryClientRouteDefinitionLocator-从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等
    • PropertiesRouteDefinitionLocator
    /**
     * 从Properties(GatewayProperties)中加载RouteDefinition信息
     * @author Spencer Gibb
     */
    public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {
    
        /**
         * 从appliccation.yml中解析前缀为spring.cloud.gateway的配置
         */
        private final GatewayProperties properties;
    
        public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
            this.properties = properties;
        }
    
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
            return Flux.fromIterable(this.properties.getRoutes());
        }
    }
    

    PropertiesRouteDefinitionLocator很简单从GatewayProperties实例获取RouteDefinition信息

    • GatewayProperties 在GatewayProperties初始化加载文中已详细描述
    • Flux 响应式编程
    • CachingRouteDefinitionLocator
    /**
     * RouteDefinitionLocator 包装实现类,实现了路由定义的本地缓存功能
     * @author Spencer Gibb
     */
    public class CachingRouteDefinitionLocator implements RouteDefinitionLocator {
    
        /**
         * 实际路由定义定位器
         */
        private final RouteDefinitionLocator delegate;
        
        private final Flux<RouteDefinition> routeDefinitions;
        /**
         * 路由定义的本地缓存
         */
        private final Map<String, List> cache = new HashMap<>();
    
        public CachingRouteDefinitionLocator(RouteDefinitionLocator delegate) {
            this.delegate = delegate;
            routeDefinitions = CacheFlux.lookup(cache, "routeDefs", RouteDefinition.class)
                    .onCacheMissResume(() -> this.delegate.getRouteDefinitions());
    
        }
    
    }   
    

    RouteDefinitionLocator包装类,缓存目标RouteDefinitionLocator 为routeDefinitions提供缓存功能

    • DiscoveryClientRouteDefinitionLocator
    public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
        /**
         * 注册中心客户端
         */
        private final DiscoveryClient discoveryClient;
        /**
         * 本地配置信息
         */
        private final DiscoveryLocatorProperties properties;
        /**
         * 路由ID前缀
         */
        private final String routeIdPrefix;
    
        public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
            this.discoveryClient = discoveryClient;
            this.properties = properties;
            if (StringUtils.hasText(properties.getRouteIdPrefix())) {
                this.routeIdPrefix = properties.getRouteIdPrefix();
            } else {
                this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
            }
        }
    
        /**
         * 通过注册中心查找服务组装路由定义信息
         * @return
         */
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
         ...代码在根据注册中心查找路由详细解析
    
        }
    }   
    

    DiscoveryClientRouteDefinitionLocator通过调用 DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组

    • CompositeRouteDefinitionLocator
    /**
     * 组合多个 RouteDefinitionLocator 的实现,为 routeDefinitions提供统一入口
     * @author Spencer Gibb
     */
    public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {
    
        /**
         * 所有路由定义定位器实例集合
         */
        private final Flux<RouteDefinitionLocator> delegates;
    
        public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
            this.delegates = delegates;
        }
    
        @Override
        public Flux<RouteDefinition> getRouteDefinitions() {
            //将各个RouteDefinitionLocator的getRouteDefinitions合并返回统一的Flux<RouteDefinition>
            return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
        }
    }
    

    CompositeRouteDefinitionLocator 的主要作用就是将各个定位器合并提供统一的getRouteDefinitions方法入口

    通过子类实现具体功能可以很清晰的看到定位器加载RouteDefinition整个流程

    graph TD
    PropertiesRouteDefinitionLocator-->|配置文件加载初始化| CompositeRouteDefinitionLocator
    RouteDefinitionRepository-->|存储器中加载初始化| CompositeRouteDefinitionLocator
    DiscoveryClientRouteDefinitionLocator-->|注册中心加载初始化| CompositeRouteDefinitionLocator
    

    最终提供通过CompositeRouteDefinitionLocator提供统一的 getRouteDefinitions方法

    RouteDefinitionLocator实例的初始化在GatewayAutoConfiguration中已经完成

    • GatewayDiscoveryClientAutoConfiguration
    @Configuration
    @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
    @AutoConfigureBefore(GatewayAutoConfiguration.class)
    @ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
    @EnableConfigurationProperties
    public class GatewayDiscoveryClientAutoConfiguration {
    
        //初始化注册中心路由定义定位器
        @Bean
        @ConditionalOnBean(DiscoveryClient.class)
        @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
        public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
                DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
            return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
        }
    
    • GatewayAutoConfiguration
       //初始化配置路由定义加载器
        @Bean
        @ConditionalOnMissingBean
        public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
            return new PropertiesRouteDefinitionLocator(properties);
        }
    
        //初始化存储路由定义加载器
        @Bean
        @ConditionalOnMissingBean(RouteDefinitionRepository.class)
        public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
            return new InMemoryRouteDefinitionRepository();
        }
    
         //初始化聚合路由定义加载器
        @Bean
        @Primary
        public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
            return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
        }
    

    在Spring-Cloud-Gateway初始化完成后需要的路由定义加载器已全部实例化完成,这样就为路由的加载创建完成了必要的条件。

    展开全文
  • Gateway网关简介及使用

    万次阅读 多人点赞 2019-10-09 20:54:12
    Gateway网关简介及使用 1. 什么是 API 网关(API Gateway) 分布式服务架构、微服务架构与 API 网关 在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计、开发、测试、部署和管理。这时,各个...
  • spring cloud gateway之filter篇

    万次阅读 多人点赞 2018-12-17 21:45:21
    在上一篇文章详细的介绍了Gateway的Predict,Predict决定了请求由哪一个路由处理,在路由处理之前,需要经过“pre”类型的过滤器处理,处理返回响应之后,可以由“post”类型的过滤器处理。 filter的作用和生命周期 ...
  • Spring Cloud Alibaba 05_使用微服务网关 Gateway 实现路由映射和API限流 注:Gateway 是 SpringCloud 官方提供的新一代网关组件,是基于Netty 的,与 Servlet 不兼容 所以在 gateway 中不能出现 Servlet 相关的...
  • Spring Cloud Gateway 之Predict篇

    万次阅读 多人点赞 2018-12-09 12:53:44
    Spring Cloud gateway工作流程 在之前的文章的Spring Cloud Gateway初体验中,大家已经对Spring Cloud Gateway的功能有一个初步的认识,网关作为一个系统的流量的入口,有着举足轻重的作用,通常的作用如下: 协议...
  • GatewayWorker

    2020-09-12 20:29:44
    composer require workerman/gateway-worker 目录结构: 0x01 Gateway类 注意:startPort设置端口,是和BusinessWorker进行连接的本地端口。 GatewayWorker类的使用 创建项目目录,然后composer下载...
  • 前面分别对 Spring Cloud Zuul 与 Spring Cloud Gateway 进行了简单的说明,它门是API网关,API网关负责服务请求路由、组合及协议转换,客户端的所有请求都首先经过API网关,然后由它将匹配的请求路由到合适的微服务...
  • spring cloud gateway之服务注册与发现

    万次阅读 多人点赞 2018-12-22 16:08:40
    在之前的文章介绍了Spring Cloud Gateway的Predict(断言)、Filter(过滤器),大家对Spring Cloud Gateway有初步的认识,其中在对服务路由转发的这一块,在之前的文章是采用硬编码的方式进行路由转发。这篇文章以...
  • 微服务网关实战——Spring Cloud Gateway

    万次阅读 多人点赞 2019-05-24 16:02:31
    作为Netflix Zuul的替代者,Spring Cloud Gateway是一款非常实用的微服务网关,在Spring Cloud微服务架构体系中发挥非常大的作用。本文对Spring Cloud Gateway常见使用场景进行了梳理,希望对微服务开发人员提供一些...
  • Dubbo结合Gateway实现微服务网关

    万次阅读 2020-09-07 01:42:18
    Dubbo结合Gateway实现微服务网关 前言 最近,我发布了Dubbo Demo项目以及Gateway网关的博客,于是奇思妙想到能不能将两者结合起来呢?首先我们可以在Dubbo的官网中看了开发者文档,它推荐使用的网关只有三种Kong、...
  • spring cloud gateway源码级讲解

    千人学习 2019-07-20 20:00:49
    本课程系统的讲解spring cloud gateway 1、spring cloud gateway的原理 2、spring cloud gateway的功能,会带着大家把官方文档过一遍 3、spring cloud gateway的搭建 4、spring cloud gateway结合注册...
  • GateWay配置

    千次阅读 2020-05-01 15:01:50
    Gateway配置 new module pom <dependencies> <dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --> <groupId>org.example</groupId> <...
  • springcloud gateway

    千次阅读 2019-06-18 22:21:12
    了解springcloud Gateway 网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而springcloud gateway作为SpringCloud官方推出的第二代网关框架,取代了Zuul网关。 <dependency> <groupId&...
  • gateway网关笔记

    千次阅读 2020-10-16 12:48:30
    gateway在项目中充当网关的作用 使用可看spring官方文档 https://spring.io/ --> Projects --> Spring Cloud --> LEARN --> Spring Cloud Gateway --> Reference Doc. Route:路由 Predicate:...
  • 服务网关配置:Gateway

    千次阅读 多人点赞 2021-02-03 17:34:48
    目录第一章 Gateway介绍1.1、什么是Gateway1.2、为啥用Gateway第二章 Gateway三大核心第三章 Gateway工作流程第四章 Gateway路由功能4.1、项目准备与启动4.2、工程搭建与测试4.3、配置自定义路由4.4、禁止默认的路由...
  • 配置websocket路径:spring.cloud.gateway.routes[7].id=testwsspring.cloud.gateway.routes[7].uri=lb:ws://iflynote-fsspring.cloud.gateway.routes[7].filters[0]=StripPrefix=1spring.cloud.gateway.routes[7]....
  • gateway服务网关

    2020-04-08 17:23:14
    gateway服务网关
  • gateway资源详解

    2020-08-31 12:01:12
    学习目标 什么是gateway 在Kubernetes环境中,...gateway 分为两种,分别是ingress-gateway和egress-gateway,分别用来处理入口流量和出口流量。gateway本质也是一个envoy pod。 资源详解 selector 1.7.0/gat
  • 八、网关Gateway

    万次阅读 2020-04-17 13:55:42
    SpringCloud推出的新一代网关Gateway.....
  • GatewayWorker流程

    千次阅读 2019-12-20 13:45:55
    GatewayWorker流程 手里的项目遇到个需求,就了解了一下GatewayWorker。本来打算用这个了,但是最后还是选择了workerman。简单说一下GatewayWorker流程吧 因为项目需求用的php做设备通信。设备客户端使用tcp进行长...
  • 微服务网关-Gateway

    万次阅读 2020-08-31 13:43:01
    微服务网关-Gateway 前言 近期做的项目,每次新增一个接口都需要提jira工单在公司的网关平台上申请接口权限。 那么什么是网关?我们为什么要使用网关呢……一些列问题在我脑海里出现。 正文 网关的简介 网关是系统的...
  • API Gateway

    千次阅读 2017-08-13 22:31:25
    API Gateway 转自:http://www.cnblogs.com/Leo_wl/p/4934036.html 原文地址:http://microservices.io/patterns/apigateway.html,以下是使用google翻译对原文的翻译。 让我们想象一下你正在建立一个使用...
  • Spring Cloud Gateway(一):认识Spring Cloud Gateway

    千次阅读 多人点赞 2018-11-11 16:19:43
    1、Spring Cloud Gateway 简介 Spring Cloud Gateway 系列目录 Spring Cloud Gateway(一):认识Spring Cloud Gateway 1.1、Spring Cloud Gateway 是什么 Spring Cloud Gateway 基于 Spring Boot 2, 是 Spring...
  • gateway的作用

    2020-09-14 15:14:56
    gateway介绍 gateway相当于所有服务的门户,将客户端请求与服务端应用相分离,客户端请求通过gateway后由定义的路由和断言进行转发,路由代表需要转发请求的地址,断言相当于请求这些地址时所满足的条件,只有同时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 64,629
精华内容 25,851
关键字:

gateway