Spring Cloud Gateway详解

119 阅读5分钟

Spring Cloud Gateway 是 Spring 生态系统中的网关服务,它基于 Spring Boot 2.x 和 Spring WebFlux 构件,并提供了一种简单而有效地方式来对外部请求进行路由和过滤。

一、路由

Spring Cloud Gateway 的核心功能是路由,它根据不同的请求路径将请求转发到一组符合条件的微服务实例。这里的路由规则类似于传统的 URL 映射,但更加强大和灵活,可以通过多种方式匹配请求路径(如正则表达式、Path Pattern、Ant Path)并进行分发。

启动一个简单的 Spring Cloud Gateway 应用程序,可以使用以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>2.2.9.RELEASE</version>
</dependency>

创建一个路由规则需要指定一个唯一的 ID 和一个目标 URI,并通过断言器来决定是否匹配该规则,例如:

spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/foo/**

在上面的示例中,我们定义了一个名为 route1 的路由规则,它会将所有以 /foo/ 开头的请求转发到 http://localhost:8081 地址,这里使用了 Path Predicate 。还可以使用其他类型的断言器来匹配请求路径、请求参数等。

二、过滤器

Spring Cloud Gateway 过滤器用于在路由请求前或路由请求后对请求和响应进行处理,包括修改请求头、请求参数、响应结果等。Spring Cloud Gateway 提供了一组内置的过滤器,包括访问日志记录、身份验证、限流等,还可以自定义过滤器来实现特定的功能。过滤器适用于有状态的操作,比如从 HTTP 请求中提取头部信息,并使用它们来确定要跳转到哪个具体的服务实例。

以下是一个简单的 Spring Cloud Gateway 过滤器实现,它将在服务器响应中添加一个 Hello World 消息,代码如下:

@Component
public class AddResponseHeaderFilter implements GatewayFilter, Ordered {
 
    private static final String HEADER_NAME = "X-Response-Foo";
    private static final String HEADER_VALUE = "Hello World!";
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            ServerHttpResponse response = exchange.getResponse();
            HttpHeaders headers = response.getHeaders();
            headers.add(HEADER_NAME, HEADER_VALUE);
        }));
    }
 
    @Override
    public int getOrder() {
        return 0;
    }
}

上面的代码中,我们首先创建了一个名为 AddResponseHeaderFilter 的类,它实现了 GatewayFilter 接口。filter 方法是该过滤器的核心逻辑,可以在这里对请求进行修改。然后,我们通过 fromRunnable 方法添加一个任务,该任务会在服务器响应时向响应头中添加一个 X-Response-Foo 的头部信息。最后,需要实现 Ordered 接口,以声明过滤器的顺序。

三、负载均衡

Spring Cloud Gateway 本身不提供负载均衡策略,而是通过集成 Spring Cloud LoadBalancer 实现。Spring Cloud LoadBalancer 是一组可扩展的轮询算法和随机算法例子,支持多种负载均衡器实现,包括 Ribbon、Nacos、Consul 和 Eureka 等。使用 Spring Cloud LoadBalancer 和 Spring Cloud Gateway 可以轻松实现高性能、高可靠性的微服务架构。

示例代码如下:

@Configuration
public class LoadBalancedConfig {
    
    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
 
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("service-provider", r -> r.path("/foo/**")
                .uri("lb://provider-service"))
            .build();
    }
}

上述代码片段中,我们首先定义了一个名为 loadBalancedWebClientBuilder 的 Bean,它基于 Spring Cloud LoadBalancer 来构建一个负载均衡的 WebClient 对象。使用 @LoadBalanced 注解会自动注入负载均衡功能。

然后,通过 customRouteLocator 方法来定义一个名为 route1 的路由规则,使用 path predicate 匹配请求路径,并将这个匹配规则应用到 lb://provider-service 地址上。这里的 provider-service 指的是具体的服务名。

四、断路器

Spring Cloud Gateway 对于微服务架构系统中的高可用性和容错性至关重要。为了避免由于故障导致的系统响应变慢或失败,Gateway 还提供了熔断功能。Spring Cloud Gateway 熔断器能够帮助我们及时发现异常和错误,从而保护整个系统不会因为单个组件的故障而完全崩溃。简单地说,一旦系统出现负载过大或错误,熔断器将停止将流量发送到该组件,并启动一个备用计划。

示例代码如下:

@Configuration
public class FallbackConfiguration {
    
    @Autowired
    private FallbackHandler fallbackHandler;
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("service-provider", r -> r.path("/foo/**")
                .filters(f -> f.circuitBreaker(c -> c.setName("myCircuitBreaker")
                    .setFallbackUri("forward:/fallback")))
                .uri("lb://provider-service"))
            .build();
    }
 
    @Bean
    public RouterFunction<ServerResponse> fallbackRouter() {
        return route(GET("/fallback"),
            req -> ServerResponse.ok().bodyValue(fallbackHandler.getFallbackResponse()));
    }
}

在上面的代码示例中,我们首先定义了一个名为 myCircuitBreaker 的断路器组件,并定义一个回退路径(Fallback Path),该组件将用于处理“服务提供方”路由规则的请求。此外,我们还实现了一个名为 fallbackRouter 的 RouterFunction,来响应熔断机制产生的事件,如超时或错误请求。

然后在 customRouteLocator 方法中,我们使用了 circuitBreaker filter 来添加断路器,在出现异常时会重定向到 fallback 路径,这里的 Fallback Path 是由 fallbackRouter 提供的,用于处理备用操作。

总结

通过以上对 Spring Cloud Gateway 的讲解,我们可以看出它的模块化、可扩展和易于集成的特点,使开发人员可以更轻松地构建微服务架构服务,并快速将它们上线。它的主要功能包括路由、过滤器、负载均衡和断路器等,都是为了实现微服务平台架构而设计的。

相关案例代码:

  1. 路由使用 示例
spring:
  cloud:
    gateway:
      routes:
        - id: route1
          uri: http://localhost:8081
          predicates:
            - Path=/foo/**
  1. 过滤器使用示例
@Component
public class AddResponseHeaderFilter implements GatewayFilter, Ordered {
 
    private static final String HEADER_NAME = "X-Response-Foo";
    private static final String HEADER_VALUE = "Hello World!";
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange).then(Mono.fromRunnable(() -> {
            ServerHttpResponse response = exchange.getResponse();
            HttpHeaders headers = response.getHeaders();
            headers.add(HEADER_NAME, HEADER_VALUE);
        }));
    }
 
    @Override
    public int getOrder() {
        return 0;
    }
}
  1. 负载均衡示例
@Configuration
public class LoadBalancedConfig {
    
    @Bean
    @LoadBalanced
    public WebClient.Builder loadBalancedWebClientBuilder() {
        return WebClient.builder();
    }
 
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("service-provider", r -> r.path("/foo/**")
                .uri("lb://provider-service"))
            .build();
    }
}
  1. 断路器示例
@Configuration
public class FallbackConfiguration {
    
    @Autowired
    private FallbackHandler fallbackHandler;
    
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
            .route("service-provider", r -> r.path("/foo/**")
                .filters(f -> f.circuitBreaker(c -> c.setName("myCircuitBreaker")
                    .setFallbackUri("forward:/fallback")))
                .uri("lb://provider-service"))
            .build();
    }
 
    @Bean
    public RouterFunction<ServerResponse> fallbackRouter() {
        return route(GET("/fallback"),
            req -> ServerResponse.ok().bodyValue(fallbackHandler.getFallbackResponse()));
    }
}