要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux。

1.gateway 和zuul对比

I am the author of spring cloud gateway. Zuul is built on servlet 2.5 (works with 3.x), using blocking APIs. It doesn't support any long lived connections, like websockets.

Gateway is built on Spring Framework 5, Project Reactor and Spring Boot 2 using non-blocking APIs. Websockets are supported and it's a much better developer experience since it's tightly integrated with Spring.

简单的来说:

  1.zuul是基于servlet 2.5,兼容servlet3.0,使用的是阻塞API,不支持长连接如websocket

  2.Gateway基于spring5,Reactor和Spring boot2使用了非阻塞API,支持websocket,和spring完美集成,对开发者友好。

  另外

  3.zuul2支持非阻塞API,但没有和spring cloud集成,且已经停止维护,不在考虑之列。

2.架构图

3.自动配置解析core spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayNoLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration,\
org.springframework.cloud.gateway.config.GatewayRedisAutoConfiguration,\
org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.cloud.gateway.config.GatewayEnvironmentPostProcessor

3.1 GatewayClassPathWarningAutoConfiguration检查前端控制器

    @Configuration
@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
protected static class SpringMvcFoundOnClasspathConfiguration { public SpringMvcFoundOnClasspathConfiguration() {
log.warn(BORDER
+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "
+ "Please remove spring-boot-starter-web dependency." + BORDER);
} } @Configuration
@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
protected static class WebfluxMissingFromClasspathConfiguration { public WebfluxMissingFromClasspathConfiguration() {
log.warn(BORDER + "Spring Webflux is missing from the classpath, "
+ "which is required for Spring Cloud Gateway at this time. "
+ "Please add spring-boot-starter-webflux dependency." + BORDER);
} }

1.若存在springmvc的前端控制器org.springframework.web.servlet.DispatcherServlet,则报警,原因是使用非阻塞的API

2.若不存在spring webflux的前端控制器org.springframework.web.reactive.DispatcherHandler,则报警,原因是需要使用非阻塞的API

3.2 网关自动配置GatewayAutoConfiguration

3.2.1 RoutePredicateHandlerMapping

    @Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
FilteringWebHandler webHandler, RouteLocator routeLocator,
GlobalCorsProperties globalCorsProperties, Environment environment) {
return new RoutePredicateHandlerMapping(webHandler, routeLocator,
globalCorsProperties, environment);
}

RoutePredicateHandlerMapping继承自AbstractHandlerMapping,在此步进行路径查找

    @Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on the management port if set
if (managmentPort != null
&& exchange.getRequest().getURI().getPort() == managmentPort.intValue()) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName()); return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
} exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); //2
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
} protected Mono<Route> lookupRoute(ServerWebExchange exchange) {//1
return this.routeLocator.getRoutes()
// individually filter routes so that filterWhen error delaying is not a
// problem
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
}); /*
* TODO: trace logging if (logger.isTraceEnabled()) {
* logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
*/
}

1.通过RouteLocator返回Route

关于Route的定义

    private Route(String id, URI uri, int order,
AsyncPredicate<ServerWebExchange> predicate,
List<GatewayFilter> gatewayFilters) {
this.id = id;
this.uri = uri;
this.order = order;
this.predicate = predicate;
this.gatewayFilters = gatewayFilters;
}

可以看出url和gatewayFilter进行了绑定

2.将Route放入ServerWebExchange的属性中。

3.2.2 FilteringWebHandler

    @Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}

参考文献:

【1】https://stackoverflow.com/questions/47092048/how-spring-cloud-gateway-is-different-from-zuul

【2】https://blog.csdn.net/xuejike/article/details/81290695

api网关揭秘--spring cloud gateway源码解析的更多相关文章

  1. Feign 系列(05)Spring Cloud OpenFeign 源码解析

    Feign 系列(05)Spring Cloud OpenFeign 源码解析 [TOC] Spring Cloud 系列目录(https://www.cnblogs.com/binarylei/p/ ...

  2. spring cloud ribbon源码解析(一)

    我们知道spring cloud中restTemplate可以通过服务名调接口,加入@loadBalanced标签就实现了负载均衡的功能,那么spring cloud内部是如何实现的呢? 通过@loa ...

  3. spring cloud ribbon源码解析(二)

    在上一篇文章中主要梳理了ribbon的执行过程,这篇主要讲讲ribbon的负载均衡,ribbon的负载均衡是通过ILoadBalancer来实现的,对ILoadBalancer有以下几个类 1.Abs ...

  4. 微服务网关实战——Spring Cloud Gateway

    导读 作为Netflix Zuul的替代者,Spring Cloud Gateway是一款非常实用的微服务网关,在Spring Cloud微服务架构体系中发挥非常大的作用.本文对Spring Clou ...

  5. .net core下,Ocelot网关与Spring Cloud Gateway网关的对比测试

    有感于 myzony 发布的 针对 Ocelot 网关的性能测试 ,并且公司下一步也需要对.net和java的应用做一定的整合,于是对Ocelot网关.Spring Cloud Gateway网关做个 ...

  6. Spring Security 解析(七) —— Spring Security Oauth2 源码解析

    Spring Security 解析(七) -- Spring Security Oauth2 源码解析   在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因 ...

  7. spring boot @Value源码解析

    Spring boot 的@Value只能用于bean中,在bean的实例化时,会给@Value的属性赋值:如下面的例子: @SpringBootApplication @Slf4j public c ...

  8. 最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)

    前言: 最近开发了Zuul网关的实现和Spring Cloud Gateway实现,对比Spring Cloud Gateway发现后者性能好支持场景也丰富.在高并发或者复杂的分布式下,后者限流和自定 ...

  9. 创建网关项目(Spring Cloud Gateway)

    创建网关项目 加入网关后微服务的架构图 创建项目 POM文件 <properties> <java.version>1.8</java.version> <s ...

随机推荐

  1. WindowsPE权威指南 第二章 小工具 PEInfo代码的C语言实现

    主程序代码 PEInfo.c #include <Windows.h> #include<Richedit.h> #include "resource.h" ...

  2. Redis讲解以及测试要点

    一.redis 简介 redis适合放一些频繁使用,比较热的数据,因为是放在内存中,读写速度都非常快,一般会应用在下面一些场景,排行榜.计数器.消息队列推送.好友关注.粉丝. 首先要知道mysql存储 ...

  3. [转]dd命令、cp命令详解+dd命令、cp命令对比 ---delong

    出处:http://blog.csdn.net/sun_app/article/details/18263299 1.dd命令详解 1)中文man手册dd的解释 NAME       dd - 转换和 ...

  4. (转)jira7.2安装、中文及破解

    转自:http://www.cnblogs.com/ilanni/p/6200875.html 本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanni ...

  5. jsp获取当前项目跟路径

    在jsp中获取当前项目的根路径: <% String basePath = request.getScheme() + "://"+ request.getServerNam ...

  6. gitlab 之 cicd

    1.使用 docker 安装 gitlab docker run -d  --hostname gitlab \        --env GITLAB_OMNIBUS_CONFIG="ex ...

  7. roadhog如何支持除development和production外的其他环境变量配置

    roadhog的build和start脚本分别对应了env/development和production,但实践中存在第三种开发环境(可能是预发或集成测试),配置和前两种也都不一样,但现在似乎没办法支 ...

  8. let,const,var

    1.const定义的变量不可以修改,而且必须初始化. 1 const b = 2;//正确 2 // const b;//错误,必须初始化 3 console.log('函数外const定义b:' + ...

  9. 基础项目构建,引入web模块,完成一个简单的RESTful API 转载来自翟永超

    简介 在您第一次接触和学习Spring框架的时候,是否因为其繁杂的配置而退却了?在你第n次使用Spring框架的时候,是否觉得一堆反复粘贴的配置有一些厌烦?那么您就不妨来试试使用Spring Boot ...

  10. Python3.* 和Python2.*的区别

    许多Python初学者都会问:我应该学习哪个版本的Python.对于这个问题,我的回答通常是“先选择一个最适合你的Python教程,教程中使用哪个版本的Python,你就用那个版本.等学得差不多了,再 ...