Spring Cloud Gateway 入门

Spring Cloud Gateway介绍

前段时间刚刚发布了Spring Boot 2正式版,Spring Cloud Gateway基于Spring Boot 2,是Spring Cloud的全新项目,该项目提供了一个构建在Spring 生态之上的API网关,包括:Spring 5,Spring Boot 2和Project Reactor。 Spring Cloud Gateway旨在提供一种简单而有效的途径来发送API,并为他们提供横切关注点,例如:安全性,监控/指标和弹性。当前最新的版本是v2.0.0.M8,正式版最近也会到来。

Spring Cloud Gateway的特征:

  • Java 8
  • Spring Framework 5
  • Spring Boot 2
  • 动态路由
  • 内置到Spring Handler映射中的路由匹配
  • 基于HTTP请求的路由匹配 (Path, Method, Header, Host, etc…)
  • 过滤器作用于匹配的路由
  • 过滤器可以修改下游HTTP请求和HTTP响应 (Add/Remove Headers, Add/Remove Parameters, Rewrite Path, Set Path, Hystrix, etc…)
  • 通过API或配置驱动
  • 支持Spring Cloud DiscoveryClient配置路由,与服务发现与注册配合使用

vs Netflix Zuul

Zuul基于servlet 2.5(使用3.x),使用阻塞API。 它不支持任何长连接,如websockets。而Gateway建立在Spring Framework 5,Project Reactor和Spring Boot 2之上,使用非阻塞API。 Websockets得到支持,并且由于它与Spring紧密集成,所以将会是一个更好的开发体验。

Spring Cloud Gateway入门实践

笔者最近研读了Spring Cloud Gateway的源码,大部分功能的实现也写了源码分析的文章,但毕竟正式版没有发布,本文算是一篇入门实践,展示常用的几个功能,期待最近的正式版本发布。

示例启动两个服务:Gateway-Server和user-Server。模拟的场景是,客户端请求后端服务,网关提供后端服务的统一入口。后端的服务都注册到服务发现Consul(搭建zk,Eureka都可以,笔者比较习惯使用consul)。网关通过负载均衡转发到具体的后端服务。

用户服务

用户服务注册到Consul上,并提供一个接口/test

依赖

需要的依赖如下:

1    <dependency>
2        <groupId>org.springframework.cloud</groupId>
3        <artifactId>spring-cloud-starter-consul-discovery</artifactId>
4    </dependency>
5
6    <dependency>
7        <groupId>org.springframework.boot</groupId>
8        <artifactId>spring-boot-starter-web</artifactId>
9    </dependency>

配置文件

 1spring:
 2  application:
 3    name: user-service
 4  cloud:
 5    consul:
 6      host: 192.168.1.204
 7      port: 8500
 8      discovery:
 9        ip-address: ${HOST_ADDRESS:localhost}
10        port: ${SERVER_PORT:${server.port}}
11        healthCheckPath: /health
12        healthCheckInterval: 15s
13        instance-id: user-${server.port}
14        service-name: user
15server:
16  port: 8005
17management:
18  security:
19    enabled: false

暴露接口

 1@SpringBootApplication
 2@RestController
 3@EnableDiscoveryClient
 4public class GatewayUserApplication {
 5
 6    public static void main(String[] args) {
 7        SpringApplication.run(GatewayUserApplication.class, args);
 8    }
 9
10    @GetMapping("/test")
11    public String test() {
12        return "ok";
13    }
14}

暴露/test接口,返回ok即可。

网关服务

网关服务提供多种路由配置、路由断言工厂和过滤器工厂等功能。

依赖

需要引入的依赖:

 1<dependency>
 2    <groupId>org.springframework.boot</groupId>
 3    <artifactId>spring-boot-actuator</artifactId>
 4</dependency>
 5//依赖于webflux,必须引入
 6<dependency>
 7    <groupId>org.springframework.boot</groupId>
 8    <artifactId>spring-boot-starter-webflux</artifactId>
 9</dependency>
10<dependency>
11    <groupId>org.springframework.cloud</groupId>
12    <artifactId>spring-cloud-gateway-core</artifactId>
13</dependency>
14//服务发现组件,排除web依赖
15<dependency>
16    <groupId>org.springframework.cloud</groupId>
17    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
18    <version>2.0.0.M6</version>
19    <exclusions>
20        <exclusion>
21            <groupId>org.springframework.boot</groupId>
22            <artifactId>spring-boot-starter-web</artifactId>
23        </exclusion>
24    </exclusions>
25</dependency>
26//kotlin依赖
27<dependency>
28    <groupId>org.jetbrains.kotlin</groupId>
29    <artifactId>kotlin-stdlib</artifactId>
30    <version>${kotlin.version}</version>
31    <optional>true</optional>
32</dependency>
33<dependency>
34    <groupId>org.jetbrains.kotlin</groupId>
35    <artifactId>kotlin-reflect</artifactId>
36    <version>${kotlin.version}</version>
37    <optional>true</optional>
38</dependency>

如上引入了kotlin相关的依赖,这里需要支持kotlin的路由配置。Spring Cloud Gateway的使用需要排除web相关的配置,引入的是webflux的引用,应用启动时会检查,必须引入。

路由断言工厂

路由断言工厂有多种类型,根据请求的时间、host、路径、方法等等。如下定义的是一个基于路径的路由断言匹配。

1    @Bean
2    public RouterFunction<ServerResponse> testFunRouterFunction() {
3        RouterFunction<ServerResponse> route = RouterFunctions.route(
4                RequestPredicates.path("/testfun"),
5                request -> ServerResponse.ok().body(BodyInserters.fromObject("hello")));
6        return route;
7    }

当请求的路径为/testfun时,直接返回ok的状态码,且响应体为hello字符串。

过滤器工厂

网关经常需要对路由请求进行过滤,进行一些操作,如鉴权之后构造头部之类的,过滤的种类很多,如增加请求头、增加请求参数、增加响应头和断路器等等功能。

 1    @Bean
 2    public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
 3        //@formatter:off
 4        return builder.routes()
 5                .route(r -> r.path("/image/webp")
 6                        .filters(f ->
 7                                f.addResponseHeader("X-AnotherHeader", "baz"))
 8                        .uri("http://httpbin.org:80")
 9                )
10                .build();
11        //@formatter:on
12    }

如上实现了当请求路径为/image/webp时,将请求转发到http://httpbin.org:80,并对响应进行过滤处理,增加响应的头部X-AnotherHeader: baz

自定义路由

上面两小节属于API自定义路由,还可以通过配置进行定义:

 1spring:
 2  cloud:
 3    gateway:
 4      locator:
 5        enabled: true
 6      default-filters:
 7      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
 8
 9      routes:
10      # =====================================
11      - id: default_path_to_http
12        uri: blueskykong.com
13        order: 10000
14        predicates:
15        - Path=/**

如上的配置定义了路由与过滤器。全局过滤器将所有的响应加上头部X-Response-Default-Foo: Default-Bar。定义了id为default_path_to_http的路由,只是优先级比较低,当该请求都不能匹配时,将会转发到blueskykong.com

kotlin自定义路由

Spring Cloud Gateway可以使用kotlin自定义路由:

 1@Configuration
 2class AdditionalRoutes {
 3
 4    @Bean
 5    fun additionalRouteLocator(builder: RouteLocatorBuilder): RouteLocator = builder.routes {
 6        route(id = "test-kotlin") {
 7            path("/image/png")
 8            filters {
 9                addResponseHeader("X-TestHeader", "foobar")
10            }
11            uri("http://httpbin.org:80")
12        }
13    }
14
15}

当请求的路径是/image/png,将会转发到http://httpbin.org:80,并设置了过滤器,在其响应头中加上了X-TestHeader: foobar头部。

服务发现组件

与服务注册于发现组件进行结合,通过serviceId转发到具体的服务实例。在前面的配置已经引入了相应的依赖。

1    @Bean
2    public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
3        return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
4    }

DiscoveryClient注入到DiscoveryClientRouteDefinitionLocator的构造函数中,关于该路由定义定位器,后面的源码分析会讲解,此处不展开。

 1spring:
 2  cloud:
 3    gateway:
 4      locator:
 5        enabled: true
 6      default-filters:
 7      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
 8      routes:
 9      # =====================================
10      - id: service_to_user
11        uri: lb://user
12        order: 8000
13        predicates:
14        - Path=/user/**
15        filters:
16        - StripPrefix=1

上面的配置开启了DiscoveryClient定位器的实现。路由定义了,所有请求路径以/user开头的请求,都将会转发到user服务,并应用路径的过滤器,截取掉路径的第一部分前缀。即访问/user/test的实际请求转换成了lb://user/test

websocket

还可以配置websocket的网关路由:

 1spring:
 2  cloud:
 3    gateway:
 4      default-filters:
 5      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
 6
 7      routes:
 8      - id: websocket_test
 9        uri: ws://localhost:9000
10        order: 9000
11        predicates:
12        - Path=/echo

启动一个ws服务端wscat --listen 9000,将网关启动(网关端口为9090),进行客户端连接即可wscat --connect ws://localhost:9090/echo

客户端的访问

上述实现的功能,读者可以自行下载源码进行尝试。笔者这里只展示访问用户服务的结果:

网关成功负载均衡到user-server,并返回了ok。响应的头部中包含了全局过滤器设置的头部X-Response-Default-Foo: Default-Bar

总结

在本文中,我们探讨了属于Spring Cloud Gateway的一些功能和组件。 这个新的API提供了用于网关和代理支持的开箱即用工具。期待Spring Cloud Gateway 2.0正式版。

源码地址

https://github.com/keets2012/Spring-Cloud_Samples

原文发布于微信公众号 - aoho求索(aohoBlog)

原文发表时间:2018-03-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linyb极客之路

使用Spring Boot实现模块化

3772
来自专栏测试开发架构之路

jmeter二次开发

http://jmeter.apache.org/download_jmeter.cgi

3911
来自专栏王清培的专栏

spring rest 容易被忽视的后端服务 chunked 性能问题

spring boot 容易被忽视的后端服务 chunked 性能问题 标签(空格分隔): springboot springmvc chunked 背景 sp...

4618
来自专栏杂烩

ganglia安装报错解决 原

1、There was an error collecting ganglia data (127.0.0.1:8652): fsockopen error: ...

811
来自专栏沈玉琛的专栏

体验Django REST framework,解读REST架构风格

写下这篇文章,一方面记录Django REST framework的体验过程,同时借此解读下REST架构风格。

1.2K55
来自专栏猿天地

Spring Boot 使用WebAsyncTask异步返回结果

在Spring Boot中(Spring MVC)下请求默认都是同步的,一个请求过去到结束都是由一个线程负责的,很多时候为了能够提高吞吐量,需要将一些操作异步化...

3872
来自专栏Golang语言社区

linux常用的内核参数的设置

.共享内存大小的设置 临时设置: 通过修改/proc/sys/kernel/shmmax参数可以达到此目的。   [root@neirong root]# ec...

2976
来自专栏Java技术栈

Spring Boot 配置加载顺序详解

使用 Spring Boot 会涉及到各种各样的配置,如开发、测试、线上就至少 3 套配置信息了。Spring Boot 可以轻松的帮助我们使用相同的代码就能使...

2113
来自专栏lgp20151222

spring boot注入error,Consider defining a bean of type 'xxx' in your configuration问题解决方案

经常出现这问题一定是非spring生态圈的@标签 没被spring引入,如mybatis等

6121
来自专栏咖啡的代码人生

Log4j 1.2.17 使用

首先下载Log4j有关的jar包,虽然现在 Log4j更新到了2.0,但是和以前的1.X版本完全不兼容,所以今天我们还是先来使用1.X的版本,等时间再久一点,...

4099

扫码关注云+社区