SpringCloud gateway原理分析

论坛 期权论坛     
选择匿名的用户   2021-5-23 23:20   403   0
<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">   &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.cloud&lt;/groupId&gt;
            &lt;artifactId&gt;spring-cloud-starter-gateway&lt;/artifactId&gt;
   &lt;/dependency&gt;
</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&#61;1
      routes:
        - id: client2
          uri: lb://client2
          predicates:
            - Path&#61;/client2/**
          filters:
            - StripPrefix&#61;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">&#64;Override
protected Mono&lt;?&gt; getHandlerInternal(ServerWebExchange exchange) {
  if (managmentPort !&#61; null &amp;&amp; exchange.getRequest().getURI().getPort() &#61;&#61; managmentPort.intValue()) {
   return Mono.empty();
  }
  exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
  return lookupRoute(exchange) //超找所有的符合条件的路由
    .flatMap((Function&lt;Route, Mono&lt;?&gt;&gt;) r -&gt; {
     exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
     exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
     return Mono.just(webHandler);// 返回要执行的过滤器执行器
    }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -&gt; {
     exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
     if (logger.isTraceEnabled()) {
      logger.trace(&#34;No RouteDefinition found for [&#34; &#43; getExchangeDesc(exchange) &#43; &#34;]&#34;);
     }
    })));
}



protected Mono&lt;Route&gt; lookupRoute(ServerWebExchange exchange) {
  return this.routeLocator
    .getRoutes() // 从路由管理器中获取所有的路由
    // 转换和连接的操作符
    .concatMap(route -&gt; Mono
      .just(route)
      .filterWhen(r -&gt; { //过滤符合条件的route
       exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
       return r.getPredicate().apply(exchange); //判断路由是否符合条件
      })
      .doOnError(e -&gt; logger.error(&#34;Error applying predicate for route: &#34;&#43;route.getId(), e))
      .onErrorResume(e -&gt; Mono.empty())
    )
    .next() //返回第一个
    .map(route -&gt; {
     validateRoute
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP