SpringCloud之Gateway的入门知识和实战
一、SpringCloud Gateway简介
1.1 什么是Spring Cloud Gateway
Spring Cloud Gateway是Spring官方基于Spring 5.0、Spring Boot 2.0和Project Reactor等技术开发的网关,Spring Cloud Gateway旨在为微服务架构提供简单、有效且统一的API路由管理方式。Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Netflix Zuul,其不仅提供统一的路由方式,并且还基于Filter链的方式提供了网关基本的功能,例如:安全、监控/埋点、限流等。
官方源码地址: https://github.com/spring-cloud/spring-cloud-gateway
官方网站地址:http://cloud.spring.io
1.2 几个核心概念
网关提供API全托管服务,丰富的API管理功能,辅助企业管理大规模的API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略(WAF)、防刷、流量、监控日志等功能。一般来说,网关对外暴露的URL或者接口信息,我们统称为路由信息。如果研发过网关中间件,或者使用或了解过Zuul的人,会知道网关的核心肯定是Filter以及Filter Chain(Filter责任链)。Spring Cloud Gateway也具有路由和Filter的概念。下面介绍一下Spring Cloud Gateway中最重要的几个概念。
路由(route)
路由是网关最基础的部分,路由信息由一个ID、一个目的url、一组断言工厂和一组Filter组成。如果路由断言为真,则说明请求的url和配置的路由匹配。
断言(predicate)
Java 8中的断言函数。Spring Cloud Gateway中的断言函数输入类型是Spring 5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自于Http Request中的任何信息,比如请求头和参数等。
过滤器(filter)
一个标准的Spring webFilter。Spring Cloud Gateway中的Filter分为两种类型的Filter,分别是Gateway Filter和Global Filter。过滤器Filter将会对请求和响应进行修改处理。
二、SpringCloud Gateway的工作原理
核心处理流程如下图所示。
Gateway的客户端会向Spring Cloud Gateway发起请求,请求首先会被HttpWebHandlerAdapter进行提取组装成网关的上下文,然后网关的上下文会传递到DispatcherHandler。DispatcherHandler是所有请求的分发处理器,DispatcherHandler主要负责分发请求对应的处理器,比如将请求分发到对应RoutePredicateHandlerMapping(路由断言处理映射器)。路由断言处理映射器主要用于路由的查找,以及找到路由后返回对应的FilteringWebHandler。FilteringWebHandler主要负责组装Filter链表并调用Filter执行一系列的Filter处理,然后把请求转到后端对应的代理服务处理,处理完毕之后,将Response返回到Gateway客户端。
总结过程如下几点:
- 客户端向网关发起请求;
- 请求被
HttpWebHandlerAdapter
拦截并组装,然后传递给DispatherHander
; DispatcherHandler
分发到对应的处理器映射器(例如RoutePredicateHandlerMapping
);- 处理器映射器根据路由信息找到对应的
FilteringWebHandler
,然后经过层层过滤器处理,把请求转到真正的处理服务器,处理完毕后,经过post
类型过滤器,最终返回给客户端。
在Filter链中,通过虚线分割Filter的原因是,过滤器可以在转发请求之前处理或者接收到被代理服务的返回结果之后处理。所有的Pre类型的Filter执行完毕之后,才会转发请求到被代理的服务处理。被代理的服务把所有请求处理完毕之后才会执行Post类型的过滤器。
值得注意
在配置路由的时候,如果不指定端口的话,http默认设置端口为80, https默认设置端口为443。Spring Cloud Gateway的启动容器目前只支持Netty。
三、SpringCloud Gateway的快速入门
- 父工程
pom.xml
<?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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
</parent>
<groupId>com.gyoomi</groupId>
<artifactId>demo-gateway-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<module>demo-gateway-with-route-locator</module>
<module>demo-gateway-with-yml-config</module>
</modules>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
- 子工程1(yml配置)
pom.xml
<?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">
<parent>
<artifactId>demo-gateway-parent</artifactId>
<groupId>com.gyoomi</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>demo-gateway-with-yml-config</artifactId>
<properties>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<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>
</dependencies>
</dependencyManagement>
<dependencies>
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>-->
<!--Spring Cloud Gateway的Starter-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
appliation.yml
server:
port: 8081
spring:
application:
name: spring-cloud-yml-gateway
cloud:
gateway:
routes:
- id: baidu_route
uri: http://baidu.com:80/
predicates:
- Path=/baidu
logging: ## Spring Cloud Gateway的日志配置
level:
org.springframework.cloud.gateway: TRACE
org.springframework.http.server.reactive: DEBUG
org.springframework.web.reactive: DEBUG
reactor.ipc.netty: DEBUG
management:
endpoints:
web:
exposure:
include: '*'
security:
enabled: false
启动类
@SpringBootApplication
public class YmlGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(YmlGatewayApplication.class, args);
}
}
- 子工程2(java代码配置)
pom.xml
<?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">
<parent>
<artifactId>demo-gateway-parent</artifactId>
<groupId>com.gyoomi</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>demo-gateway-with-route-locator</artifactId>
<properties>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<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>
</dependencies>
</dependencyManagement>
<dependencies>
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>-->
<!--Spring Cloud Gateway的Starter-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
application.yml
server:
port: 8080
spring:
application:
name: spring-cloud-gateway
logging: ## Spring Cloud Gateway的日志配置
level:
org.springframework.cloud.gateway: TRACE
org.springframework.http.server.reactive: DEBUG
org.springframework.web.reactive: DEBUG
reactor.ipc.netty: DEBUG
management:
endpoints:
web:
exposure:
include: '*'
security:
enabled: false
启动类及网关路由配置
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
/**
* 基本转发
* 当访问http://localhost:8080/jd
* 转发到http://jd.com
*
* @param builder b
* @return RouteLocator
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/jd")
.uri("http://jd.com:80/")
.id("jd_route")
).build();
}
}
- 启动测试效果
使用浏览器分别访问http://localhost:8080/jd
和http://localhost:8081/baidu
。我们会发现,浏览器会跳转到京东和百度的首页,即http://wwjd.com
, http://www.baidu.com
。
值得注意
Spring Cloud Gateway提供了一个gateway actuator,该EndPiont提供了关于Filter及routes的信息查询以及指定route信息更新的Rest API接口。可以在application.yml中配置开启,配置如下所示。
management:
endpoints:
web:
exposure:
include: '*'
security:
enabled: false
这样通过访问: http://ip:port/actuator/gateway/routes
这样的url来获取相关的路由信息。如子项目的1的访问路由和结果如下所示。
其他