java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Gateway基础

Spring Gateway基础教程

作者:高垚淼

本文主要总结Spring Gateway的基础用法,内容包括网关、Spring Gateway工作流程、Spring Cloud Gateway搭建、路由配置方式、负载均衡实现、断言工厂这几个部分,感兴趣的朋友跟随小编一起看看吧

本文主要总结Spring Gateway的基础用法,内容包括网关、Spring Gateway工作流程、Spring Cloud Gateway搭建、路由配置方式、负载均衡实现、断言工厂这几个部分

1. 网关

1.1 网关介绍

在微服务架构中,一个系统会被拆分为多个微服务,那么作为客户端如何去调用这些微服务呢?如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用,这样会产生很多问题:

为了解决上述问题引入了网关概念:所谓的API网关就是指系统的统一入口,提供内部服务的路由中转,为客户端提供统一的服务,一些与业务本身功能无关的公共逻辑可以在这里实现,例如认证、鉴权、监控、路由转发等。

1.2 网关对比

Zuul、Nginx+Lua 和 Spring Cloud Gateway 都可以用作API网关,但它们在不同方面有一些不同之处,包括性能、扩展性、功能和用途。以下是它们的主要比较:

1.3 Spring Gateway

Spring Cloud Gateway是一个用于构建API网关的开源项目,它是Spring Cloud生态系统的一部分。API网关是微服务架构中的关键组件之一,用于管理和路由传入的请求,提供了一种集中化的访问点,可以实现诸如路由、负载均衡、身份验证、安全性、监控、限流、重试等功能。Spring Cloud Gateway提供了一种现代、动态、灵活且功能强大的方式来处理这些任务。

以下是Spring Cloud Gateway的一些主要特点和功能:

Spring Cloud Gateway是建立在Spring Framework和Spring Boot的基础上的,因此与Spring生态系统的其他组件无缝集成。它为构建微服务架构中的API网关提供了灵活、高性能和现代的解决方案。

特点:

1.4 核心概念

在Spring Gateway中:

id: example_route uri: example.com predicates:

断言(Predicate):谓词是用于匹配HTTP请求的条件。谓词可以基于请求的各种属性,如路径、主机、标头等。例如,Path谓词可以匹配请求路径。

举例:定义一个谓词,要求请求路径必须以/api开头:

predicates:

举例:定义一个过滤器,向响应标头中添加X-Custom-Header标头:

filters:

这些组件一起构成了Spring Gateway的核心功能,允许您定义路由规则、请求匹配条件以及请求和响应的处理操作。

1.6 总结

SpringCloud Gateway使用的是WebFlux中的reactor-netty响应式编程组件,底层使用Netty通讯框架。

2. Spring Gateway工作流程

2.1 官网上的核心工作流程

核心流程图如下:

核心流程:

核心点:

2.2 Spring Gateway执行流程

如上图所示,当使用Spring Gateway处理请求时,它经历以下流程:

如果路由断言成功,表示当前请求匹配了某个路由规则。此时,将会由FilteringWebHandler创建一个过滤器链,并按照链的顺序调用这些过滤器。过滤器可以在请求到达后端服务之前或响应返回给客户端之前对请求进行修改、验证或记录日志等操作。

这个流程允许Spring Gateway进行请求的路由和过滤,以实现对请求的控制和处理。通过配置不同的路由规则和过滤器,可以根据请求的性质来决定如何处理请求,例如路由到不同的后端服务、添加安全性措施或改变请求和响应的内容。

总结

Gateway的核心流程就是:路由转发+执行过滤器链

3. Spring Cloud Gateway搭建

3.1 Gateway搭建

搭建一个cloud-alibaba-gateway项目,因为使用了spring cloud 所以需要注意版本间的匹配,这里可以通过阿里的云原生脚手架去获取适合的版本:[start.aliyun.com/]

搭建Spring Gateway项目之前需要一些前置搭建微服务注册中心(Nacos,Consul,Eureka等),这里我使用Nacos进行演示,Nacos的搭建流程可以参考:[https://www.jb51.net/article/184641.htm]

该案例的完整代码可以在gitee项目中获取:[gitee.com/lei-qinghua…]

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ts</groupId>
    <artifactId>cloud-alibaba-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cloud-alibaba-gateway</name>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
        <spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version>
        <spring-cloud.version>2021.0.5</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.ts.demo.DemoApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

注意:引入Gateway一定要删除spring-boot-starter-web依赖,否则会发生冲突无法引入。

yml

server:
  port: 9999
spring:
  application:
    name: cloud-gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true  # 开启了spring gateway
      routes:
        - id: nacos-provider #服务id,对应nacos中注册的服务名
          uri: http://localhost:9003/nacos-provider #访问的uri地址
          predicates:
            - Path=/ts/** #断言,对请求进行匹配,只有包含/ts的路径才能通过断言

controller (微服务cloud-alibaba-provider-9003)

这里我们搭建了另外一个微服务cloud-alibaba-provider-9003作为服务的提供者来验证网关是否生效,这个微服务的逻辑非常简单,使用HashMap模拟一个一个数据库的获取操作如下:

@RequestMapping("/ts")
@RestController
public class DataController {
    @Value("${server.port}")
    String serverPort;
    public static HashMap<Long,String> hashMap = new HashMap<>();
    static {
        hashMap.put(1l,"鼠标");
        hashMap.put(2l,"键盘");
        hashMap.put(3l,"耳机");
    }
    @GetMapping("info/{id}")
    public JsonResult<String> msbSQL(@PathVariable("id") Long id) {
        JsonResult<String> result = new JsonResult<>(200,"ServerPort: "+serverPort+":"+hashMap.get(id));
        return result;
    }
    @GetMapping("/timeout")
    public JsonResult<String> timeout(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return new JsonResult<>(200,"ServerPort: "+serverPort);
    }
}

测试:[http://localhost:9999/ts/timeout]

如下图所示,我们通过微服务提供者的url对服务进行访问,而是通过gateway网关的路径对微服务进行访问成功了,就说明我们的网关搭建成功了。

3.2 总结

这里以一个简单的例子展示了Spring Gateway网关的基础搭建和测试过程,相关的服务搭建都是在本地完成的,完整的代码请参考我的gitee项目:[gitee.com/lei-qinghua…]

4. Gateway路由配置方式

在第三节中我们用yml文件对Gateway的路由方式进行了配置,实际上Gateway还可以通过Java代码的方式来进行路由配置。

4.1 Gateway Config

通过@Bean 注入一个RouteLocator,代码如下:

package com.example.cloudalibabagateway.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayConfig {
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes =routeLocatorBuilder.routes();
        routes.route("path_ts",r -> r.path("/ts/**").uri("http://localhost:9003/nacos-provider"));
        return routes.build();
    }
}

4.2 通过yml文件配置

server:
  port: 9999
spring:
  application:
    name: cloud-gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: nacos-provider
          uri: http://localhost:9003/nacos-provider
          predicates:
            - Path=/ts/**

5. Gateway实现负载均衡

5.1 什么是负载均衡

微服务系统的负载均衡是一种机制,用于在微服务架构中均匀分配网络请求和流量到不同的微服务实例,以确保各个服务的资源充分利用,提高系统的性能、可用性和稳定性。在微服务架构中,通常存在多个相同或相似的微服务实例,每个实例都提供相同的服务接口,但可能运行在不同的主机或容器上。

以下是微服务系统中负载均衡的一些关键概念和特点:

微服务系统的负载均衡是确保整个系统运行顺畅的重要组成部分。它有助于避免单点故障,提高系统的可用性,并允许系统根据需求自动扩展。选择适当的负载均衡策略和工具对于构建稳健的微服务系统至关重要。

5.2 自动负载均衡

Gateway还提供了和Zuul类似的自动路由规则,具体配置如下:

server:
  port: 9999
spring:
  application:
    name: cloud-gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true # 开启自动路由功能,根据服务名自动创建routes

测试:[http://localhost:9999/nacos-provider/info/1]

我们直接通过spring gateway的服务地址和服务提供者nacos-provider的服务名组成的url地址,就可以以负载均衡的方式访问nacos-provider的服务。

5.3 手动负载均衡

自动负载均衡存在一个问题就是需要暴露每一个服务的服务名称,因此可以采用手动负载均衡的方式来避免暴露微服务的服务名称。

yml配置:

server:
  port: 9999
spring:
  application:
    name: cloud-gateway-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: nacos-provider
          uri: lb://nacos-provider # 开启负载均衡,服务名称为nacos-provider
          predicates: # 断言,放开所有路径
            - Path=/**

6. Gateway断言Predicate

Gateway断言可以理解为当满足条件后才会进行转发,总结就是Predicate就是为了实现一组匹配规则,让请求过来找到相应的Route进行处理。

6.1 断言种类

Spring Cloud Gateway支持多种路由断言(Route Predicates)类型,用于匹配和路由HTTP请求。以下是一些常见的路由断言类型:

Path Route Predicate(路径匹配):根据请求的路径进行匹配。

predicates:

Path=/api/**

这将匹配所有以/api/开头的路径。

Host Route Predicate(主机匹配):根据请求的主机名进行匹配。

predicates:

Host=example.com

这将匹配主机名为example.com的请求。

Method Route Predicate(HTTP方法匹配):根据HTTP请求方法进行匹配。

predicates:

Method=GET

这将匹配HTTP GET请求。

Header Route Predicate(请求头匹配):根据请求头信息进行匹配。

predicates:

Header=Authorization, Bearer .+

这将匹配包含Authorization头且值以Bearer开头的请求。

Query Route Predicate(查询参数匹配):根据请求的查询参数进行匹配。

predicates:

Query=name, john

这将匹配包含name=john的查询参数的请求。

Cookie Route Predicate(Cookie匹配):根据请求的Cookie信息进行匹配。

predicates:

Cookie=sessionId, .+

这将匹配包含名为sessionId的Cookie的请求。

Combining Predicates(组合匹配):你可以组合多个路由断言来创建更复杂的匹配条件。

这将匹配主机为example.com且路径以/api/开头的请求。

这些路由断言允许你根据请求的不同属性(如路径、主机、请求头、HTTP方法等)进行匹配和路由,从而更灵活地控制请求的路由和处理。你可以在Spring Cloud Gateway的路由配置中定义这些路由断言,以满足你的具体需求。

7. Gateway的Filter

路由过滤器允许以某种方式修改传入的http请求或传出的HTTP响应,路由过滤器的范围是特定的路由Spring Cloud Gateway包含许多内置的Gateway Filter工厂。

7.1 内置Filter

7.1.1 内置过滤器分类

Gateway内置的Filter生命周期分为两种:pre(业务逻辑之前)、post(业务逻辑之后)

Gateway本身自带的Filter分为2种:GateWayFilter(单一)、GlobalFilter(全局)

Spring Cloud Gateway提供了多个内置的过滤器(Filters),这些过滤器允许你在请求和响应的生命周期中执行各种操作,例如请求路由、修改请求和响应、增加头信息等。以下是一些常见的内置过滤器:

这些内置过滤器可以通过Spring Cloud Gateway的路由配置文件进行配置,从而对请求和响应进行自定义处理。你可以根据具体需求组合和配置这些过滤器,以满足你的应用程序的需求。此外,你也可以编写自定义过滤器来执行更高度定制的操作。过滤器在Gateway中扮演了非常重要的角色,帮助你实现请求的路由和处理逻辑。

7.1.2 内置过滤器配置

Spring Gateway提供了许多内置的过滤器,用于执行常见的网关任务,例如鉴权、请求转发、重定向等。你可以在Spring Gateway的配置中添加这些内置过滤器来满足你的需求。以下是如何配置内置过滤器的一些示例:

鉴权过滤器:用于对请求进行身份验证和授权,你可以使用AddRequestHeader过滤器来添加认证信息到请求头中。

spring:
  cloud:
    gateway:
      default-filters:
        - name: AddRequestHeader
          args:
            X-Request-Auth: some-auth-token

3. 重定向过滤器:用于将请求重定向到其他路径或URL。你可以使用RedirectTo过滤器来执行重定向操作。

spring:
  cloud:
    gateway:
      routes:
        - id: my_redirect_route
          uri: http://example.com
          predicates:
            - Path=/redirect
          filters:
            - RedirectTo=302:http://new-location.com
 

4. 请求转发过滤器:用于将请求转发到其他服务或路径。你可以使用ForwardTo过滤器来执行请求转发。

spring:
  cloud:
    gateway:
      routes:
        - id: my_forward_route
          uri: http://example.com
          predicates:
            - Path=/forward
          filters:
            - ForwardTo=http://forward-service.com
 

5. 添加响应头过滤器:用于在响应中添加额外的头信息。你可以使用AddResponseHeader过滤器来添加响应头。

spring:
  cloud:
    gateway:
      default-filters:
        - name: AddResponseHeader
          args:
            X-Response-Header: some-value
 

这只是一些内置过滤器的示例,Spring Gateway提供了更多的内置过滤器,你可以根据你的需求在配置中使用它们。通过合理配置内置过滤器,你可以实现许多常见的网关功能,而无需自行编写复杂的逻辑。

7.2 自定义Filter

要创建自定义过滤器(Custom Filter)来扩展Spring Cloud Gateway的功能,你需要遵循一些步骤。自定义过滤器可以用于执行各种自定义操作,例如鉴权、日志记录、修改请求和响应等。以下是创建自定义过滤器的一般步骤:

下面我们以创建一个全局过滤器来展示如何创建自定义过滤器,要创建自定义的全局过滤器,你需要实现Spring Cloud Gateway的 GlobalFilter 接口。以下是创建一个简单的全局自定义过滤器的步骤:

以下是一个示例自定义全局过滤器的代码:

import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono&lt;Void&gt; filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 在请求处理之前执行自定义逻辑
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 在响应中添加自定义的HTTP头
        response.getHeaders().add("X-Custom-Header", "CustomHeaderValue");
        // 修改请求或响应内容
        ServerHttpRequest modifiedRequest = request.mutate()
                .header("X-Modified-Header", "ModifiedValue")
                .build();
        ServerWebExchange modifiedExchange = exchange.mutate()
                .request(modifiedRequest)
                .build();
        // 执行链中的下一个过滤器或处理器
        return chain.filter(modifiedExchange).then(Mono.fromRunnable(() -&gt; {
            // 在请求处理完成后执行自定义逻辑
            // 这里可以对响应进行进一步处理
        }));
    }
    @Override
    public int getOrder() {
        // 指定过滤器的执行顺序,可以是负数、零、正数,数字越小,执行顺序越靠前
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

在上面的示例中,CustomGlobalFilter 是一个全局过滤器,它在请求处理前和请求处理后执行自定义逻辑。你可以在 filter 方法中访问请求、响应,修改它们的内容,添加自定义HTTP头,以及执行其他自定义逻辑。getOrder 方法用于指定过滤器的执行顺序,数字越小,执行顺序越靠前。

确保将 CustomGlobalFilter 类放在Spring Boot应用程序的类路径下,Spring会自动识别并应用它。这样,你的自定义全局过滤器就会在请求到达Spring Cloud Gateway时生效。

到此这篇关于Spring Gateway基础教程的文章就介绍到这了,更多相关Spring Gateway基础内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文