文章目录
- 一、简介
- 1.3 特性
- 二、工作原理
- 三、配置路由谓词工厂和网关过滤工厂
- 四、 结合注册中心和配置中心使用
一、简介
Spring Cloud Gateway 是Spring Cloud 生态全新项目,基于Spring 5、Spring Boot 2.X、Project Reactor实现的API网关,旨在为微服务提供简单高效的API路由管理方法。
Spring Cloud Gateway 作为Spring Cloud 生态中的网关,目标是代替Zuul 1.X。Spring Cloud 2.X版本目前仍未对Zuul 2.X高性能版本进行集成,仍使用的是非Reactor的老版本Zuul网关。
- 目前Spring Cloud dependencies 最新版本Hoxton.SR8 仍使用的是Zuul 1.3.1
- Zuul 2.x 高性能Reactor版本本身与18年5月开源,目前最新版本2.1.9
为了提高网关性能,Spring Cloud Gateway基于WebFlux框架实现,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
1.1 术语
- Route: Gateway的基本构建模块,由ID、目标URL、谓词集合和过滤器集合定义。
- Predicate: Java8 Funciton Predicate,输入类型是 SpringFramework
ServerWebExchange
,可以匹配HTTP请求的所有内容,比如标头或参数。 - Filter:使用特定工厂构造的Spring Framework
GatewayFilter
实例,可以在发送下游请求之前或之后修改请求或响应。
1.3 特性
- 动态路由:能够匹配任何请求属性;
- 可以对路由指定 Predicate(断言)和 Filter(过滤器);
- 集成Hystrix的断路器功能;
- 集成 Spring Cloud 服务发现功能;
- 易于编写的 Predicate(断言)和 Filter(过滤器);
- 请求限流功能;
- 支持路径重写
1.4 Spring Cloud Gateway与Spring Cloud Zuul
Spring Cloud Zuul
Springcloud 2.x 版本到目前为止中所集成的Zuul版本(1.x),采用的是Tomcat容器,使用的是传统的Servlet IO处理模型。
servlet由servlet container进行生命周期管理。container启动时构造servlet对象并调用servlet init()进行初始化;container关闭时调用servlet destory()销毁servlet;container运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service()。
弊端:servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下这种模型是适用的,但是一旦并发上升,线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单的业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势。
所以Springcloud Zuul 是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet(DispatcherServlet),并由该servlet阻塞式处理处理。所以Springcloud Zuul无法摆脱servlet模型的弊端。
Webflux模型
Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。官方结构图:
Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。而Webflux的Loop线程,正好就是著名的Reactor 模式IO处理模型的Reactor线程,如果使用的是高性能的通信框架Netty,这就是Netty的EventLoop线程。
1.5 如何集成Gateway
使用Gateway只需要简单引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
二、工作原理
处理流程:
- Gateway接受客户端请求;
- 网关处理程序映射确定请求与路由匹配,匹配成功则将其发送到网关Web处理程序;
- Web处理程序处理程序通过特定于请求的过滤器链运行请求:
- 请求经过 Filter 过滤器链,执行 pre 处理逻辑,如修改请求头信息等。
- 发出代理请求,请求被转发至下游服务并返回响应。
- 响应经过 Filter 过滤器链,执行 post 处理逻辑。
- 向客户端响应应答。
注意,在没有端口的路由中定义的URI,HTTP和HTTPS URI的默认端口值分别为80和443。
- DispatcherHandler:所有请求的调度器,负载请求分发
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Nullable
private List<HandlerResultHandler> resultHandlers;
public DispatcherHandler() {
}
public DispatcherHandler(ApplicationContext applicationContext) {
this.initStrategies(applicationContext);
}
@Nullable
public final List<HandlerMapping> getHandlerMappings() {
return this.handlerMappings;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.initStrategies(applicationContext);
}
# 初始、校验HandlerMapping并按order排序
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
ArrayList<HandlerMapping> mappings = new ArrayList(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
//遍历handlerMappings ,根据exchange找到对应的handler
// 对于Gateway 会找到对应的RoutePredicateHandlerMapping
public Mono<Void> handle(ServerWebExchange exchange) {
return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
return mapping.getHandler(exchange);
}).next().switchIfEmpty(this.createNotFoundError())如果遍历不到结果,则切换到错误处理
.flatMap((handler) -> {
//通过HandlerAdapter调用handler,
//gateway使用的 SimpleHandlerAdapter
return this.invokeHandler(exchange, handler);
}).flatMap((result) -> {//对响应进行处理
return this.handleResult(exchange, result);
});
}
private <R> Mono<R> createNotFoundError() {
return Mono.defer(() -> {
Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler");
return Mono.error(ex);
});
}
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
Iterator var3 = this.handlerAdapters.iterator();
while(var3.hasNext()) {
HandlerAdapter handlerAdapter = (HandlerAdapter)var3.next();
if (handlerAdapter.supports(handler)) {
//调用handler的handle方法处理请求
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
//根据result获取对应的结果处理handler并处理结果
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return this.getResultHandler(result).handleResult(exchange, result).checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]").onErrorResume((ex) -> {
return result.applyExceptionHandler(ex).flatMap((exResult) -> {
String text = "Exception handler " + exResult.getHandler() + ", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
return this.getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
});
});
}
private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
if (this.resultHandlers != null) {
Iterator var2 = this.resultHandlers.iterator();
while(var2.hasNext()) {
HandlerResultHandler resultHandler = (HandlerResultHandler)var2.next();
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
}
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}
}
- RoutePredicateHandlerMapping:路由谓语匹配器,用于路由的查找,以及找到路由后返回对应的WebHandler,DispatcherHandler会依次遍历HandlerMapping集合进行处理
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final FilteringWebHandler webHandler;
private final RouteLocator routeLocator;
private final Integer managementPort;
private final RoutePredicateHandlerMapping.ManagementPortType managementPortType;
public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
this.webHandler = webHandler;
this.routeLocator = routeLocator;
this.managementPort = getPortProperty(environment, "management.server.");
this.managementPortType = this.getManagementPortT