SpringCloud_Gateway网关
文章目录
- 概述
- 简介
- 特性
- 与Zuul的区别
- Zuul 1.x模型
- GateWay模型
- 核心概念
- Route 路由
- Predicate 断言
- Filter 过滤
- 工作流程
- 配置
- 参考Demo
概述
简介
SpringCloud全家桶中有个很重要的组件就是网关,在1.X版本中采用Zuul,但在2.X版本中,Zuul的升级一直跳票,SpringCloud自己研发了GateWay替代Zuul。
SpringCloud Gateway使用的是Webflux中的reactor-netty响应式编程组件,底层使用了Netty通讯框架。
特性
- 基于Spring Framework 5,Project Reactor和SpringBoot2.0进行构建
- 动态Route,能够匹配任何请求属性
- 对Route指定Predicate和Filter
- 集成Hystrix断路器功能
- 集成SpringCloud服务发现功能
- 易于编写Predicate和Filter
- 请求限流
- 路径重写
与Zuul的区别
- Zuul是一个基于阻塞IO的API Gateway
- Zuul 1.x基于Servlet2.5使用阻塞架构,不支持任何长连接(如WebSocket),设计模式和Nginx较像,每次IO操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第一次加载较慢的情况,使得Zuul的性能相对较差。
- Zuul 2.x理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。Zuul 2.x的性能较Zuul有较大的提升。在性能方面,根据官方提供的基准测试,SpringCloud Gateway的RPS是Zuul的1.6倍。
- SpringCloud Gateway基于Spring Framework 5,Project Reactor和SpringBoot2.0进行构建
- SpringCloud Gateway还支持WebSocket,并且与Spring紧密集成拥有更好的开发体验。
Zuul 1.x模型
Zuul 1.x采用Tomcat容器,使用传统的Servlet IO模型。
Servlet的生命周期:
- container启动时构造servlet对象并调用init()进行初始化
- container运行时接受请求,并为每个请求分配一个线程(一般从线程池获取空闲线程),然后调用service()
- container关闭时调用destroy()销毁servlet
上述模式的缺点:
servlet是一个简单的网络IO模型,当请求进入servlet container时,container就会为其绑定一个线程,在并发不高的场景下,这种模型是适用的,但是一旦高并发,线程数量就会上涨,而线程资源代价是昂贵的(上下文切换,内存消耗大),严重影响请求处理时间。在一些简单业务场景下,不希望每个request分配一个线程,只需要一个或几个线程就能应对极大的并发请求,这种业务场景下servlet模型没有优势。
GateWay模型
传统的web框架,比如springmvc等都是基于Servlet API与Servlet容器基础上运行的。但是在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一个典型的异步非阻塞模型,它的核心是基于Reactor相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty,UnderTow及支持Servlet3.1的容器上。非阻塞式+函数式编程。
核心概念
Route 路由
路由是构建网关的基本模块,它由ID、目标URI,一系列的Predicate和Filter组成,如果Predicate为true则匹配该路由。
Predicate 断言
开发人员可以匹配HTTP请求中的所有内容(例如请求头或者请求参数),如果请求与断言相匹配则进行路由。
Filter 过滤
使用过滤器,可以在请求被路由前或者之后进行修改。
工作流程
客服端向GateWay发出请求,然后在Gateway Handler Mapping中找到请求匹配的路由,将其发送到Gateway Web Handler。
Handler再通过指定的过滤器链将请求发送到实际的服务执行业务逻辑。过滤器可以设置在业务逻辑之前或者之后。
Filter在pre类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等。在post类型的过滤器中可以做响应内容、响应头的修改、日志输出、流量监控等。
配置
pom
org.springframework.cloud
spring-cloud-starter-gateway yaml
server:
port: 9527spring:
application:name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
#- After=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Before=2020-02-21T15:51:37.485+08:00[Asia/Shanghai]
#- Between=2020-02-21T15:51:37.485+08:00[Asia/Shanghai],2020-02-21T15:52:37.485+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
#- Host=127.0.0.1
#- Method=GET
#- Query=username,\d+
eureka:
instance:hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
Filter
@Component
@Slf4j
public class MyLogGatewayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("come in global filter: {}", new Date());
ServerHttpRequest request = exchange.getRequest();
String uname = request.getQueryParams().getFirst("uname");
if (uname == null) {
log.info("用户名为null,非法用户");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
// 放行
return chain.filter(exchange);
}
/**
* 过滤器加载的顺序 越小,优先级别越高
*
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
参考Demo
https://github.com/zzyybs/atguigu_spirngcloud2020
还没有评论,来说两句吧...