入门概念
客户端向 Spring Cloud Gateway 发出请求。如果Gateway Handler Mapping确定请求与路由匹配,则将其发送到Gateway Web Handler 处理程序。此处理程序通过特定于请求的Fliter链运行请求。在过滤器链上线执行pre部分逻辑,然后执行代理服务,然后支线post部分逻辑。 所以在执行一个过滤器时流程是这样的 pre→proxied service→post,如下图所示:
过滤器作用
- Filter在pre类型的过滤器可以做参数效验、权限效验、流量监控、日志输出、协议转换等。
- Filter在post类型的过滤器可以做响应内容、响应头的修改、日志输出、流量监控等
- 这两种类型的过滤器有着非常重要的作用。
网关核心点
- Route(路由) 路由是构建网关的基础模块,它由ID,目标URI,包括一些列的断言predicates和过滤器filter组成,如果断言为true则匹配该路由
- Predicate(断言) 参考的是Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),请求与断言匹配则进行路由
- Filter(过滤) 指的是Spring框架中GateWayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改。
- 三个核心点连起来: 当用户发出请求到达Gateway,Gateway会通过一些匹配条件,定位到真正的服务节点,并在这个转发过程前后,进行一些及细化控制。其中Predicate就是我们匹配的条件,而Filter可以理解为一个过滤器,有了这两个点,再加上目标URI,就可以实现一个具体的路由了。
- 总结核心流程为:执行过滤器链pre逻辑→路由转发→执行过滤器链post逻辑
IDEA项目搭建
1. 新建网关模块gateway-app
2. 确定版本对应关系
因为GateWay属于SpringCloud的,所以我们要导入对应依赖,一定要注意版本关系:
版本对应地址:
Spring Cloud
我这里使用的是SpringBoot 2.3.12.RELEASE的版本所以配合的是SpringCloud的Hoxton.SR5版本
注意:引入GateWay一定要删除spring-boot-starter-web依赖,因为gateway 使用的是webflux 使用spring-boot-starter-web会导致无法启动
3. 在父项目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>
<!--这里需要注意:要使用2.4以下的版本,目前(2022.3.20)以上的版本会报错-->
<!--java.lang.NoClassDefFoundError: org/springframework/boot/context/properties/ConfigurationBeanFactory-->
<!--参考链接:https://blog.csdn.net/qq_36448800/article/details/119225687-->
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>AlibabaNacos</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<java.version>1.8</java.version>
<spring-cloud-alibaba-version>2.2.7.RELEASE</spring-cloud-alibaba-version>
<spring-cloud-openfeign-version>2.2.7.RELEASE</spring-cloud-openfeign-version>
<spring-cloud-version>Hoxton.SR5</spring-cloud-version>
</properties>
<dependencies>
<!--公共引入依赖的地方-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>${spring-cloud-openfeign-version}</version>
</dependency>
</dependencies>
<!--使用alibaba nacos需要在父项目中添加如下行-->
<dependencyManagement>
<dependencies>
<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>
<!--spring cloud Hoxton.SR5-->
<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>
<!--子模块引入-->
<modules>
<module>nacos-provider</module>
<module>gateway-app</module>
</modules>
</project>
4. 子模块gateway-app 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--指向父模块,形成关系-->
<parent>
<groupId>org.example</groupId>
<artifactId>AlibabaNacos</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>gateway-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway-app</name>
<description>gateway-app</description>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--注入阿里巴巴nacos服务注册发现相关包-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- spring cloud gateway依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
</project>
5. 创建服务提供者子模块nacos-provider
该模块支持多实例部署,以测试负载均衡
服务需要注册到注册中心nacos
服务名称:nacos-provider
端口:8081/8083
提供访问接口
@RestController
public class TestController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/test/getServerPort")
public String getServerPort() {
return "Hello Nacos Discovery Port:" + serverPort;
}
}
配置如下:
spring.application.name=nacos-provider
spring.cloud.nacos.discovery.server-addr=192.168.43.11:8848
management.endpoints.web.exposure.include=*
6. 在网关子项目gateway-app中配置properties
server.port=8888
spring.application.name=gateway-app
# 注册发现服务nacos
spring.cloud.nacos.discovery.server-addr=192.168.43.11:8848
# 配置发现的服务自动配置路由转发
spring.cloud.gateway.discovery.locator.enabled=true
# 配置自定义路由转发id,不能重复
spring.cloud.gateway.routes[0].id=nacos-provider
# 配置路由转发地址,http://开头代表转发的服务地址。 如果是lb://服务名称,则是负载均衡转发
spring.cloud.gateway.routes[0].uri=http://localhost:8081
# 断言的第一种写法
#spring.cloud.gateway.routes[0].predicates[0].name=Path
#spring.cloud.gateway.routes[0].predicates[0].args.pattern=/test/**
# 断言的第二种写法
spring.cloud.gateway.routes[0].predicates[0]=Path=/test/**
7. 启动服务提供者类,先提供8081服务
从访问地址可以看出,服务提供者已正常
8. 启动网关服务测试
从图上可以看出通过8888端口,也就是网关也能正常访问服务,说明服务以通过网关转发成功了。
9. 负载均衡测试
服务提供者和网关服务都通过注册中心注册服务,然后网关通过拉取注册中心服务实例,进行负载均衡调用,所以这里需要有注册中心支持。
需要修改网关服务配置文件
# 配置路由转发地址,http://开头代表转发的服务地址。 如果是lb://服务名称,则是负载均衡转发
spring.cloud.gateway.routes[0].uri=lb://nacos-provider
需要修改网关服务器启动类加服务注册发现支持
@SpringBootApplication
//启用服务注册发现客户端,这样才能通过nacos获取和注册服务
@EnableDiscoveryClient
public class GatewayAppApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayAppApplication.class, args);
}
}
然后启动服务提供者8081和8083服务,保证能正常访问
注意:服务提供者也需要服务注册发现支持
然后启动网关服务测试从网关访问,多访问几次看看返回端口是否有变化,如果有,则说明负载均衡以生效
10. 代码方式配置路由
除了上述我们使用了配置文件的方式配置路由,spring cloud gateway 还支持以代码的方式配置路由,这种方式可以实现动态的路由方式。 当然如果是静态的配置,推荐还是通过配置文件来配置, 这样就可以通过配置中心来实现热加载。
要用代码的方式来配置路由,我们需要创建一个Configuration类,并且返回一个RouteLocator类实例的Bean给SpringBean工厂。 如下:
@Configuration
public class GatewayRouteConfig {
/*
* 配置了一个id为path_msb1的路由规则
* 当访问地址http://localhost:8888/test/**
* 就会转发到lb://nacos-provider/ 的任何地址
*/
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
// 构建多个路由routes
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
// 具体路由地址
routes.route("code-route", predicateSpec -> predicateSpec.path("/**").uri("lb://nacos-provider")).build();
// 返回所有路由规则
return routes.build();
}
}