<p>cloud-gateway源码分析:</p>
<p>gateway-filter、global-filter:<a href="https://blog.csdn.net/weixin_42073629/article/details/106934370">https://blog.csdn.net/weixin_42073629/article/details/106934370</a></p>
<p>NettyRoutingFilter、NettyWriteResponseFilter: <a href="https://blog.csdn.net/weixin_42073629/article/details/106934611">https://blog.csdn.net/weixin_42073629/article/details/106934611</a></p>
<h2>前置说明</h2>
<p>本文源码基于 <code>springcloud Hoxton.SR8</code> 版本. 以下分析仅代表个人的理解, 如有错误, 欢迎探讨.</p>
<h2><a name="t2"></a><a id="_7"></a>使用说明</h2>
<p>以spring一贯的作风, 用户使用的模式都是约定俗成的, 也就是引入<code>spring-cloud-starter-gateway</code> 依赖, 然后就可以愉快的自动配置了. 但是这里有一个要说的点, springcloud gateway是只能使用在 webflux上面, 也就是说如果引入的springmvc依赖, 那么需要修改,不然只能使用zuul了.</p>
<pre class="blockcode"><code class="language-XML"> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</code></pre>
<p>接下来就是根据自己的需求配置一些 路由的策略或者条件</p>
<pre class="blockcode"><code>
spring:
cloud:
gateway:
discovery:
locator:
enabled: false #表明gateway开启服务注册和发现的功能,并且spring cloud gateway自动根据服务发现为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务。
lowerCaseServiceId: true #是将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了),比如以/service-hi/*的请求路径被路由转发到服务名为service-hi的服务上。
filters:
- StripPrefix=1
routes:
- id: client2
uri: lb://client2
predicates:
- Path=/client2/**
filters:
- StripPrefix=1
</code></pre>
<h2><a name="t3"></a><a id="_43"></a>原理介绍</h2>
<p><a id="_45"></a>配置的加载</p>
<p>gateway的自动装配类主要在<code>GatewayAutoConfiguration</code>, 其配置了<code>GatewayProperties</code>, <code>FilteringWebHandler</code>, <code>RouteLocator</code>, <code>RouteDefinitionLocator</code>, 以及过滤器工厂和路由工厂等bean的配置</p>
<p>然后, 我们在配置文件中的路由配置的会被自动加载到 <code>GatewayProperties</code>, 然后在转换为<code>RouteDefinition</code> 存储在 <code>GatewayProperties#routes</code>中</p>
<p>下面的图是调试中一个<code>RouteDefinition</code> , 其 主要包含了 predicate 和 filters<br><img alt="在这里插入图片描述" src="https://beijingoptbbs.oss-cn-beijing.aliyuncs.com/cs/5606289-ab5efaf2dd999021810b7d39677a147a.png"></p>
<p><a id="_55"></a>路由的获取</p>
<p>首先我们的入口在 <code>org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler</code> .</p>
<p><code>AbstractHandlerMapping</code> 这个类我想应该大家看着很熟, 因为它很像<code>springmvc</code> 里面的 <code>handlerMapping</code>. 我认为这是 Spring团队想要webflux 和 springmvc 以相同的结构, 这样大家可以没有太大的学习成本来上手.</p>
<p>这边接下来会走到 <code>org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal</code>, 这个类时gateway 实现的 <code>AbstractHandlerMapping</code> 来用于实现网关路由功能</p>
<pre class="blockcode"><code class="language-java">@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
if (managmentPort != null && exchange.getRequest().getURI().getPort() == managmentPort.intValue()) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
return lookupRoute(exchange) //超找所有的符合条件的路由
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
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) {
return this.routeLocator
.getRoutes() // 从路由管理器中获取所有的路由
// 转换和连接的操作符
.concatMap(route -> Mono
.just(route)
.filterWhen(r -> { //过滤符合条件的route
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange); //判断路由是否符合条件
})
.doOnError(e -> logger.error("Error applying predicate for route: "+route.getId(), e))
.onErrorResume(e -> Mono.empty())
)
.next() //返回第一个
.map(route -> {
validateRoute |
|