api网关揭秘--spring cloud gateway源码解析

时间:2021-08-07 23:18:40

要想了解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.架构图

api网关揭秘--spring cloud gateway源码解析

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

api网关揭秘--spring cloud gateway源码解析

关于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://*.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. &period;net core下,Ocelot网关与Spring Cloud Gateway网关的对比测试

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

  6. Spring Security 解析&lpar;七&rpar; —— Spring Security Oauth2 源码解析

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

  7. spring boot &commat;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. 创建网关项目&lpar;Spring Cloud Gateway&rpar;

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

随机推荐

  1. 深入理解和应用display属性(二)

    四.inline-block 此类元素是inline + block的合体 1) margin和padding都有效:width和height都有效: .inline{ display: inline ...

  2. 原始的2文件的makefile错误

    从来没系统的看过makefile文档,平时属于复制模板,用完即忘,下午尝试按自己的理解写一个最简单的makefile,含2个.c文件,1个.h文件,费了个把小时,参考别人的文章才弄出来,特记录. ma ...

  3. 在github上搭建博客(使用Jekyll)

    简单说,只需要三步,就可以在 Github 搭建起一个博客: 在 Github 上建一个名为 xxx.github.io 的库: 把看中了的 Jekyll 模板 clone 到本地: 把这个模板 pu ...

  4. POSIX多线程——基本线程管理函数介绍

    POSIX基本的几个线程管理函数见下表: ------------------------------------------------------------------------------- ...

  5. PHP数据库扩展mysqli的函数试题

    1.mysqli链接数据库的方式是什么? 2.mysqli获取链接错误号的属性是什么? 3.mysqli获取链接错误信息的属性是什么? 4.mysqli执行sql语句的函数是什么? 5.mysqli获 ...

  6. &lbrack;Linux&rsqb; Vim 撤销 回退 操作

    在vi中按u可以撤销一次操作 u   撤销上一步的操作      Ctrl+r 恢复上一步被撤销的操作 注意:        如果你输入“u”两次,你的文本恢复原样,那应该是你的Vim被配置在Vi兼容 ...

  7. Oracle 12c的自增列Identity Columns

    在Oracle的12c版本中,Oracle实现了类似MySQL中的auto_increment的自增列,下面我们看一起Oracle是怎么实现的. Oracle Database 12c Enterpr ...

  8. delphi中Webbrowser疑难问题集锦&lt&semi;转&gt&semi;

    1.获得网页中变量值      htm中<script> var currID=123</script>      程序中可以这么调用 id := Form1.WebBrows ...

  9. Apache Cordova vs Adobe PhoneGap&colon; the differences and which one to use

    http://www.makehybridapps.com/2014/06/09/cordova-vs-phonegap-the-differences-and-which-one-to-use/

  10. Nodejs学习笔记(十七)—浮点运算decimal&period;js

    前言 开发过程中免不了有浮点运算,JavaScript浮点运算的精度问题会带来一些困扰 JavaScript 只有一种数字类型 ( Number ) JavaScript采用 IEEE 754 标准双 ...