一.soul网关引入的依赖分析

从上图可以看到我红线划分五个依赖区域

1.soul-common包:这里不是很重要,我们大概看一下他的作用就好了

从上图中可以看出,这个包里主要定义了一个常量,枚举类,配置类,自定义的DTO对象

2.soul-metrics这些依赖包主要是监控暴露出来的代码,这里也不是很重要,先略过

3.最重要的就是插件部分 soul-plugin依赖包,这里包含了你项目中会用到的插件源码

4.websocket和sync部分依赖包: 主要是网关和soul后台管理系统同步配置信息的

5.soul-web包也很重要,里面是soul网关的请求入口类,和一些拦截器,配置信息类.

二.请求流程:

可以看到exchange里面包含着request信息和response信息.

plugins插件里面会告诉你需要执行的有多少个插件

1.首先请求会到SoulWebHandler类里面的execute方法中

public Mono<Void> execute(final ServerWebExchange exchange) {return Mono.defer(() -> {//循环执行插件if (this.index < plugins.size()) {SoulPlugin plugin = plugins.get(this.index++);//判断插件是否跳过执行Boolean skip = plugin.skip(exchange);if (skip) {return this.execute(exchange);}//调用插件执行逻辑return plugin.execute(exchange, this);}return Mono.empty();});}

2.执行插件代码

可以看到spring cloud项目一共需要执行10个插件,其中3,4,7是我自定义的插件

3.GlobalPlugin插件:

 @Overridepublic Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {final ServerHttpRequest request = exchange.getRequest();final HttpHeaders headers = request.getHeaders();final String upgrade = headers.getFirst("Upgrade");SoulContext soulContext;//判断是否是websocket同步的配置请求if (StringUtils.isBlank(upgrade) || !"websocket".equals(upgrade)) {//正常请求需要构建soulContextsoulContext = builder.build(exchange);} else {final MultiValueMap<String, String> queryParams = request.getQueryParams();soulContext = transformMap(queryParams);}exchange.getAttributes().put(Constants.CONTEXT, soulContext);return chain.execute(exchange);}

继续看DefaultSoulContextBuilder类中的build方法

 public SoulContext build(final ServerWebExchange exchange) {ServerHttpRequest request = exchange.getRequest();String path = request.getURI().getPath();//根据请求的路径匹配到配置的元数据MetaData metaData = MetaDataCache.getInstance().obtain(path);if (Objects.nonNull(metaData) && metaData.getEnabled()) {exchange.getAttributes().put(Constants.META_DATA, metaData);}//构建本次请求的SoulContext上下文对象return Optional.ofNullable(metaData).map(e -> decoratorMap.get(e.getRpcType())).orElse(decoratorMap.get(RpcTypeEnum.HTTP.getName())).decorator(buildDefault(request), metaData);}

4.spring cloud plugin插件

 protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {if (Objects.isNull(rule)) {return Mono.empty();} else {SoulContext soulContext = (SoulContext)exchange.getAttribute("context");assert soulContext != null;//取出后台管理系统配置的选择器规则对象SpringCloudRuleHandle ruleHandle = (SpringCloudRuleHandle)GsonUtils.getInstance().fromJson(rule.getHandle(), SpringCloudRuleHandle.class);//取出后台管理系统配置的选择器对象SpringCloudSelectorHandle selectorHandle = (SpringCloudSelectorHandle)GsonUtils.getInstance().fromJson(selector.getHandle(), SpringCloudSelectorHandle.class);if (!StringUtils.isBlank(selectorHandle.getServiceId()) && !StringUtils.isBlank(ruleHandle.getPath())) {//调用spring cloud ribbon对象从eureka注册中心获取注册服务实例ServiceInstance serviceInstance = this.loadBalancer.choose(selectorHandle.getServiceId());if (Objects.isNull(serviceInstance)) {Object error = SoulResultWrap.error(SoulResultEnum.SPRINGCLOUD_SERVICEID_IS_ERROR.getCode(), SoulResultEnum.SPRINGCLOUD_SERVICEID_IS_ERROR.getMsg(), (Object)null);return WebFluxResultUtils.result(exchange, error);} else {//根据服务实例负载均衡获取真正的请求服务的URL信息URI uri = this.loadBalancer.reconstructURI(serviceInstance, URI.create(soulContext.getRealUrl()));//构建真正的请求URL,这里有BUG,需要注意String realURL = this.buildRealURL(uri.toASCIIString(), exchange.getRequest().getURI().getQuery());exchange.getAttributes().put("httpUrl", realURL);exchange.getAttributes().put("httpTimeOut", ruleHandle.getTimeout());return chain.execute(exchange);}} else {Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_CONFIG_SPRINGCLOUD_SERVICEID.getCode(), SoulResultEnum.CANNOT_CONFIG_SPRINGCLOUD_SERVICEID.getMsg(), (Object)null);return WebFluxResultUtils.result(exchange, error);}}}

5.webClientPlugin插件

 @Overridepublic Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);assert soulContext != null;String urlPath = exchange.getAttribute(Constants.HTTP_URL);if (StringUtils.isEmpty(urlPath)) {Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);return WebFluxResultUtils.result(exchange, error);}//获取后台管理系统配置的超时时间long timeout = (long) Optional.ofNullable(exchange.getAttribute(Constants.HTTP_TIME_OUT)).orElse(3000L);//重试时间int retryTimes = (int) Optional.ofNullable(exchange.getAttribute(Constants.HTTP_RETRY)).orElse(0);log.info("The request urlPath is {}, retryTimes is {}", urlPath, retryTimes);HttpMethod method = HttpMethod.valueOf(exchange.getRequest().getMethodValue());WebClient.RequestBodySpec requestBodySpec = webClient.method(method).uri(urlPath);//构建request的handlereturn handleRequestBody(requestBodySpec, exchange, timeout, retryTimes, chain);}

6.插件中主要介绍上面三个插件,经过插件后,就进入reactor.netty.http.client 进行异步调用下游服务接口.具体的源码信息在reactor-netty里面.本章节就不进行介绍了

soul 网关源码解析相关推荐

  1. Soul网关源码解析目录

    Soul网关源码解析目录 Soul网关源码解析文章列表     对用Java写的高性能网关:Soul,进行一波学习和研究,下面是相关的文章记录 掘金 了解与初步运行 Soul网关源码解析(一) 概览 ...

  2. Soul网关源码解析(二)代理Http请求

    如何读开源项目:对着文档跑demo,对着demo看代码,懂一点就开始试,有问题了问社区. 文章目录 今日目标: 一.从官方文档开始 1.接入说明: 2.网关需要引入代理插件 3.Http 服务接入网关 ...

  3. Soul网关源码解析(三)代理Dubbo服务

    文章目录 目标 一.使用 soul 代理 dubbo 服务 1.dubbo 服务接入网关 1.1 springboot 项目接入方式 1.2 spring 项目接入方式 2.配置 dubbo 插件 3 ...

  4. soul网关源码解析-环境搭建

    项目功能简介 支持各种语言(http协议),支持 dubbo,springcloud协议. 插件化设计思想,插件热插拔,易扩展. 灵活的流量筛选,能满足各种流量控制. 内置丰富的插件支持,鉴权,限流, ...

  5. Soul网关源码阅读(八)路由匹配初探

    Soul网关源码阅读(八)路由匹配初探 简介      今日看看路由的匹配相关代码,查看HTTP的DividePlugin匹配 示例运行      使用HTTP的示例,运行Soul-Admin,Sou ...

  6. Soul网关源码阅读(七)限流插件初探

    Soul网关源码阅读(七)限流插件初探 简介     前面的文章中对处理流程探索的差不多了,今天来探索下限流插件:resilience4j 示例运行 环境配置     启动下MySQL和redis d ...

  7. Soul 网关源码阅读(六)Sofa请求处理概览

    Soul 网关源码阅读(六)Sofa请求处理概览 简介     今天来探索一下Sofa请求处理流程,看看和前面的HTTP.Dubbo有什么异同 Sofa示例运行 PS:如果请求加上参数运行不成功,请更 ...

  8. Soul网关源码阅读(十)自定义简单插件编写

    Soul网关源码阅读(十)自定义简单插件编写 简介     综合前面所分析的插件处理流程相关知识,此次我们来编写自定义的插件:统计请求在插件链中的经历时长 编写准备     首先我们先探究一下,一个P ...

  9. Soul网关源码阅读(九)插件配置加载初探

    Soul网关源码阅读(九)插件配置加载初探 简介     今日来探索一下插件的初始化,及相关的配置的加载 源码Debug 插件初始化     首先来到我们非常熟悉的插件链调用的类: SoulWebHa ...

最新文章

  1. python中接口测试垃圾数据如何清理_一个六年经验的python后端是怎么学习用java写API的(2)Extracter,微信文章抓取清洗入库...
  2. PostgreSQL增强版命令行客户端(pgcli)
  3. 如何更新Postgresql的Jsonb数组
  4. 全新iPhone“Pro”命名要实锤:新增配色是“原谅色”本色吧?
  5. shell foreach 拼接字符串_FIND_IN_SET 及IN 处理逗号间隔的字符串参数
  6. nedc和epa续航里程什么意思_了解 NEDC 之后 我发现电动车的续航还是得实测
  7. Xcode 真机 iPhone is not available 及 is busy 解决
  8. tcp连接python_python网络编程--TCP连接的三次握手(三报文握手)与四次挥手
  9. hdu 3987 - 最小割最少割边
  10. 苹果手机如何关闭自动续费_手机APP会员自动续费怎么办?教你一招快速关闭!...
  11. 2018工业互联网峰会在京召开
  12. 继电器控制模块的一些知识
  13. chrom,firefox,ie不能上网,百度浏览器却可以。。。
  14. google翻译破解大综合
  15. SqlDataReader转换为DataTable
  16. 通用pe 装linux,U盘通用PE安装CentOS
  17. 42步进电机与57步进电机
  18. 开源:基于COF屏的雕刻机方案控制开源GRBL_ESP32
  19. nlp学习--专家系统总结-专家系统基础
  20. 非参数估计-parzen窗估计和k近邻估计

热门文章

  1. 罗振宇向左,吴晓波向右
  2. 干货!手把手教你如何快速了解一个行业--游戏产业概况
  3. 普源DG1022U信号发生器技术参数
  4. 工程项目建设数字化管理解决方案
  5. vivado编译报错:[IP_Flow 19-167] Failed to deliver one or more file(s).
  6. 张艾迪(创始人):梦想与未来
  7. CentOS 安装 laradock 以及运行 Laravel 项目
  8. npm配置国内镜像(淘宝镜像)
  9. 码云图床失效解决方案
  10. snmp trap安装配置