当前位置:   article > 正文

Spring-cloud-gateway 源码浅析_spring cloud gateway源码解析

spring cloud gateway源码解析

一、概述

        Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬,基于spring WebFlux 构建的API网关,Spring Cloud Gateway 提供了一种简单有效路由到API的方式,并为这些API提供了多种横切关注点,例如:安全性,监控/指标和弹性。Spring Cloud Gateway 的底层主要涉及两大核心技术Spring web Filter chain 和 和Spring WebFlux。

      Filter是一个Servlet规范组件;一个请求可以在Http请求到达Servlet前被一个或多个Filter处理,Servlet处理完后返回给Filter,最后返回给用户。

     WebFlux它是一个异步非阻塞式的web框架,它的作用不是提升接口请求时间,而是在一些阻塞的场景【例如请求DB,等待DB响应数据、打开大文件等】,可以把线程给其它请求使用,从而提升系统吞吐量。Gateway属于网络IO密集型【网关转发请求到下游服务】,通过WebFlux有效的提升网关转发的吞吐量。

二、Spring Cloud Gateway相关概念

路由:这是网关的基本构成模块,由一个id,一个目标uri,一组断言工厂和一组过滤器组成。如果路由中断言返回为true,则该路由被匹配。
断言:java8中的断言函数,输入类型是  Spring Framework ServerWebExchange,这会让你匹配到来自于HTTP请求的任何东西,例如headers或者其他参数
过滤器:这些GatewayFilter的实例是有一个指定的工厂构造,通过过滤器,你可以在发送响应下游请求的前后处理并修改这些请求和响应

三、Spring Cloud Gateway 工作原理

以下图表高度概况了Spring Cloud Gateway的工作原理:

       客户端发送请求到Spring Cloud Gateway,如果Gateway Handler Mapping 判定 这个请求和路由是匹配的,则这个请求会被发送到Gateway Web Handler。Handler通过与该请求匹配的过滤器链执行该请求。过滤器被虚线隔开的原因是这些过滤可以在代理请求被发送的前后进行处理。当代理请求被创建前,所有 “pre"过滤器的逻辑将会被执行。当代理请求被创建后,所有"post"的过滤器逻辑将会被执行。

四、Spring Cloud Gateway 简单例子

1、pom配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.6.9</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.example</groupId>
   <artifactId>springCloudGatewayDemo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>springCloudGatewayDemo</name>
   <description>springCloud测试项目</description>
   <properties>
      <java.version>1.8</java.version>
      <spring-cloud.version>2021.0.3</spring-cloud.version>
   </properties>
   <dependencies>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-gateway</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>
   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

2、applicaiton.yml

server:
  port: 8080
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
        #netty 路由过滤器,http或https开头
        - id: app1-route
          uri: http://www.baidu.com
          predicates:
            - Path=/app1/**
          filters:
            #转发请求时去掉1级前缀
            - StripPrefix=1

3、启动类

package com.example.springCloudGatewayDemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import reactor.core.publisher.Mono;

@SpringBootApplication
public class SpringCloudGatewayDemoApplication {

   public static void main(String[] args) {
      SpringApplication.run(SpringCloudGatewayDemoApplication.class, args);
   }

}

4、启动应用 访问地址http://localhost:8080/app1/  则网关代理到了http://www.baidu.com

五、源码分析

      1、当请求到达SpringCloudGateway 的时候,netty会通过nio的形式的处理请求,首先会调用到io.netty.channel.ChannelInboundHandlerAdapter#channelRead 读取网络数据,并最终调用至org.springframework.web.server.handler.FilteringWebHandler#handle进而调用到org.springframework.web.server.handler.DefaultWebFilterChain#filter,DefaultWebFilterChain这个类实例化后的对象保了系统中已注册过的过滤器。执行filter方法,会按照一定次序调用org.springframework.web.server.WebFilter子类中的filter方法。直至所有已注册的过滤器filter方法执行完毕之后,开始执行org.springframework.web.server.WebHandler子类的handler方法。当执行至org.springframework.web.reactive.DispatcherHandler#handle时会调用到org.springframework.web.reactive.HandlerMapping子类的getHandler方法。当调用至org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler时会调用到org.springframework.web.reactive.handler.AbstractHandlerMapping子类的getHandlerInternal方法,当调用至org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal方法时,开始进入springCloudGateway拦截处理流程中。

   2、org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal方法体如下:

 在此方法中对ServerWebExchange对象设置了路由执行阶段exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());表示接下来开始查找Gateway handler mapper。并开始执行lookupRoute方法

    2、org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute

 在该方法中通过org.springframework.cloud.gateway.route.RouteLocator的子类getRoutes方法获取路由。子类获取路由对象的方式有三种方式:

 第一种是通过缓存获取路由对象、第二种则是通过复合对象获取路由即通过Flux<RouteLocator>【其他RouteLocator】对象获取路由 第三种是通过RouteDefinitions来获取路由对象,在配置文件中配置的路由本质上也是通过RouteDefinitions这种方式被加载到springCloudGateway中的。

得到路由对象之后,设置执行流程exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());记录当前期开始执行断言功能。并开始执行该路由对象java.util.function.Predicate子类的test方法,例如上述例子中定义的Path断言便是在此此处执行 Path断言的工厂类为org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory,执行的方法为apply方法,进而执行test方法。

 org.springframework.cloud.gateway.handler.AsyncPredicate

 当test返回值为true时,将路由传递给下一步,并执行validateRoute函数,对路由进行一个验证,如果test返回false则就此终止。

至此返回webhandler对象。

org.springframework.web.reactive.DispatcherHandler#handle

 如果执行mapping.getHandler(exchange);如果未获取到handler则返回“404 No matching handler"错误信息。

如果收集到与该请求匹配的handler方法,则执行invokeHandler,

org.springframework.web.reactive.DispatcherHandler#invokeHandler

 在该方法中会遍历所有handlerAdapter对象,并执行handle 方法。

当执行至org.springframework.cloud.gateway.handler.FilteringWebHandler#handle方法时,便进入springCloudGateway 过滤器逻辑处理部分。

org.springframework.cloud.gateway.handler.FilteringWebHandler

 

当FilteringWebHandler对象在spring中被注入时会将globalFilters属性进行赋值。

当执行handler方法时,首先通过路由对象获取GatewayFilter对象,然后

会根据globalFilters属性和GatewayFilter对象,进行创建

DefaultGatewayFilterChain对象,并执行过滤器链中所有过滤器的filter方法.此时combined对象中先存储了GlobalFilter对象后拼接了GatewayFilter对象

org.springframework.cloud.gateway.handler.FilteringWebHandler.DefaultGatewayFilterChain#filter

在该方法中遍历filter并创建 DefaultGatewayFilterChain对象,实现递归调用GatewayFilter子类对象的filter方法此时先执行全局过滤器,后执行网关过滤器。当执行至 org.springframework.cloud.gateway.handler.FilteringWebHandler.GatewayFilterAdapter#filter方法,会执行GlobalFilter子类的filter 方法。

 当执行完所有的handler方法之后,返回HandlerResult 对象。并执行HandlerResult对象的hanlerResult方法

org.springframework.web.reactive.DispatcherHandler#handle

 至此springCloudGateway流程执行结束。并将exchange和result消息传递给下一个流程。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/708557
推荐阅读
相关标签
  

闽ICP备14008679号