SpringCloud生态的网关(第二代),未来会取代Zuul(第一代),Gateway是基于Netty(网络通信框架,可以实现高性能的服务端和客户端)、Reactor以及WebFlux(基于Reactive的Web框架)构建
SpringCloudGateway的优点
- 性能强劲:是第一代网关Zuul1.x的1.6倍
参考:https://www.imooc.com/article/285068 - 功能强大:内置了很多实用工具,比如转发、监控、限流等
- 设计优雅:容易扩展
SpringCloudGateway的缺点
- 依赖Netty与Webflux,不是Servlet编程模型,有一定的适应成本
- 不能在Servlet容器下工作,也不能构建war包
- 不支持SpringBoot1.x
一、编写SpringCloudGateway
1.1、创建项目
1.2、在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.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itmuch</groupId>
<artifactId>gateway</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gateway</name>
<description>小程序网关</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 使用Zipkin之后,Sleuth就不需要了,因为Zipkin已经包含了Sleuth -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.5.0</version>
<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.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>0.9.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
1.3、 在application.yml中添加属性
server:
port: 8040
spring:
application:
name: gateway
zipkin:
base-url: http://localhost:9411/
sleuth:
sampler:
#抽样率,默认0.1(10%),设置为1.0表示所有的数据都会上报给Zipkin
probability: 1.0
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 让gateway通过服务发现组件找到其他微服务
enabled: true
routes:
# - id: user_route
# uri: lb://user-center
# predicates:
# - Path=/users/**
# - id: content_route
# uri: lb://content-center
# predicates:
# - Path=/shares/**,/admin/**
#自定义路由谓词工厂
- id: after_route
uri: lb://content-center
predicates:
#时间格式必须按照以下格式,参考(注意idea编码集必须改为utf8)TimeBetweenRoutePredicateFactory#main
- TimeBetween=上午9:00, 下午10:00
filters:
#自定义过滤器工厂类PreLogGatewayFilterFactory,随意传两个参数a和b,a=config.getName(),b=config.getValue()
- PreLog=a,b
management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always
logging:
level:
org.springframework.cloud.gateway: trace
1.4、测试运行
访问内容中心/shares/1
原路径http://localhost:8010
现在使用gateway网关路径http://localhost:8040,网关转发成功,实现了反向代理
转发规律:访问${GATEWAYY_URL}/{微服务X}/** 会转发到微服务X的/**路径
二、SpringCloudGateway核心概念
- Route(路由):SpringCloudGateway的基础元素,可简单理解成一条转发的规则。包含:ID、目标URL、Predicate集合以及Filter集合
- Predicate(谓词):即java.util.function.Predicate,SpringCloudGateway使用Predicate实现路由的匹配条件
- Filter(过滤器):修改请求以及响应
2.1、路由谓词工厂
参考:https://www.imooc.com/article/290804
2.2、自定义路由谓词工厂
实现需求:设置网络访问的时间段,超出不可访问
2.2.1、在application.yml中添加属性
spring:
application:
name: gateway
zipkin:
base-url: http://localhost:9411/
discoveryClientEnabled: false
sleuth:
sampler:
# 抽样率,默认是0.1(10%)
probability: 1.0
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 让gateway通过服务发现组件找到其他微服务
enabled: true
routes:
#自定义路由谓词工厂
- id: after_route
uri: lb://content-center
predicates:
#时间格式必须按照以下格式,参考(注意idea编码集必须改为utf8)TimeBetweenRoutePredicateFactory#main
- TimeBetween=上午9:00, 下午5:00
附录:IDEA修改编码位utf8的方法
2.2.2、创建配置类
package com.itmuch.gateway;
import lombok.Data;
import java.time.LocalTime;
@Data
public class TimeBeweenConfig {
private LocalTime start;
private LocalTime end;
}
2.2.3、创建自定义工程类
package com.itmuch.gateway;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
@Component
public class TimeBetweenRoutePredicateFactory
extends AbstractRoutePredicateFactory<TimeBeweenConfig> {
public TimeBetweenRoutePredicateFactory() {
super(TimeBeweenConfig.class);
}
/**
* 路由谓词工厂的核心方法
* @param config
* @return
*/
@Override
public Predicate<ServerWebExchange> apply(TimeBeweenConfig config) {
LocalTime start = config.getStart();
LocalTime end = config.getEnd();
return exchange -> {
LocalTime now = LocalTime.now();
return now.isAfter(start) && now.isBefore(end);
};
}
/**
* 控制配置类TimeBeweenConfig和配置文件application#predicates的映射关系
* @return
*/
@Override
public List<String> shortcutFieldOrder() {
//TimeBeweenConfig类的两个属性start和end分别对应application中TimeBetween的9:00和17:00两个参数
return Arrays.asList("start", "end");
}
//测试输出SpringCloudGateway的时间格式
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
System.out.println(formatter.format(LocalTime.now()));
}
}
2.2.4、测试运行结果
当前时间下午6:49,网关可访问时间为上午9:00-下午5:00所以访问结果应该为404
2.3、过滤器工厂
参考:https://www.imooc.com/article/290816
2.4、自定义过滤器工厂
过滤器生命周期
- Pre:Gateway转发请求之前
- Post:Gateway转发请求之后
2.5、编写过滤器工厂
需求:进入工厂时记录日志
2.5.1、application.yml中添加filter属性
spring:
application:
name: gateway
zipkin:
base-url: http://localhost:9411/
discoveryClientEnabled: false
sleuth:
sampler:
# 抽样率,默认是0.1(10%)
probability: 1.0
cloud:
nacos:
discovery:
server-addr: localhost:8848
gateway:
discovery:
locator:
# 让gateway通过服务发现组件找到其他微服务
enabled: true
routes:
#自定义路由谓词工厂
- id: after_route
uri: lb://content-center
predicates:
#时间格式必须按照以下格式,参考(注意idea编码集必须改为utf8)TimeBetweenRoutePredicateFactory#main
- TimeBetween=上午9:00, 下午10:00
filters:
#自定义过滤器工厂类PreLogGatewayFilterFactory,随意传两个参数a和b,a=config.getName(),b=config.getValue()
- PreLog=a,b
2.5.2、创建自定义过滤器工厂类PreLogGatewayFilterFactory
务必注意,自定义的过滤器工厂类必须以GatewayFilterFactory结尾
package com.itmuch.gateway;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
@Slf4j
@Component
public class PreLogGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return ((exchange, chain) -> {
//获取application中配置的两个参数的值,config.getName()=a;config.getValue()=b
log.info("请求进来了...{},{}", config.getName(), config.getValue());
ServerHttpRequest modifiedRequest = exchange.getRequest()
.mutate()
.build();
ServerWebExchange modifiedExchange = exchange.mutate()
.request(modifiedRequest)
.build();
return chain.filter(modifiedExchange);
});
}
}
2.5.3、测试运行结果
访问http://localhost:8040/shares/2
2.6、全局过滤器
参考:https://www.imooc.com/article/290821
三、监控SpringCloudGateway
参考:https://www.imooc.com/article/290828
三、调试、排查技巧总结
参考:https://www.imooc.com/article/290824