下载编译

git clone git@github.com:dromara/soul.gitcd soulmvn clean package install -Dmaven.test.skip=true -Dmaven.javadoc.skip=true -Drat.skip=true -Dcheckstyle.skip=true

运行

1. 启动一个127.0.0.1:3306,用户名为root,密码为空的mysql实例,用于保存soul元数据

2. 使用idea打开maven项目soul

3. 在【soul-admin】模块下,找到启动类 org.dromara.soul.admin.SoulAdminBootstrap 并运行,默认监听的是9095端口

4. 在【soul-bootstrap】模块下,找到启动类 org.dromara.soul.bootstrap.SoulBootstrapApplication 并运行,默认监听的是9195端口

5. 使用浏览器打开 soul管理界面

6. 默认的用户名/密码是 admin/123456

使用方法

1. 启动一个本地服务, 采用默认8080端口

curl http://localhost:8080/message -d '{"body": "1"}' -X POST -H 'Content-Type: application/json'success%

2. 在本地服务(SpringBoot)上添加soul依赖

(1) 添加pom依赖

<dependency><groupId>org.dromara</groupId><artifactId>soul-spring-boot-starter-client-springmvc</artifactId><version>2.2.1</version></dependency>

(2)添加yml,注册本地服务到soul网关

soul:http:# soul 管理界面入口adminUrl: http://127.0.0.1:9095# 本地服务监听的端口port: 8080# soul 网关代理的uri前缀contextPath: /http# 本地服务的名称appName: http# 代理全部请求, 不需要配置        @org.dromara.soul.client.springmvc.annotation.SoulSpringMvcClientfull: true

(3)验证网关转发功能

curl http://localhost:9195/http/message -d '{"body": "1"}' -X POST -H 'Content-Type: application/json'success%

带着问题看源码系列-如何完成HTTP请求转发

通过观察管理界面,猜想完成转发的是一个名为divide插件。在classpath里搜索 DividePlugin,在soul-plugin-divide模块中找到类 org.dromara.soul.plugin.divide.DividePlugin

在 org.dromara.soul.plugin.divide.DividePlugin#doExecute(ServerWebExchange, SoulPluginChain, SelectorData, RuleData) 方法中打一个断点

再次访问网关转发功能, 被断点拦截

final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT); // 获取soul上下文assert soulContext != null; // 断言 soul上下文不为空final DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class); // 找到此次请求对应的规则配置final List<DivideUpstream> upstreamList = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(selector.getId()); // 找到此次请求可以访问的服务列表if (CollectionUtils.isEmpty(upstreamList)) {log.error("divide upstream configuration error: {}", rule.toString());Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);return WebFluxResultUtils.result(exchange, error);}final String ip = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress(); // 获取客户端访问的主机名DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip); // 通过负载均衡算法和主机名在可访问的服务列表中此次请求应该访问的服务if (Objects.isNull(divideUpstream)) {log.error("divide has no upstream");Object error = SoulResultWrap.error(SoulResultEnum.CANNOT_FIND_URL.getCode(), SoulResultEnum.CANNOT_FIND_URL.getMsg(), null);return WebFluxResultUtils.result(exchange, error);}// set the http urlString domain = buildDomain(divideUpstream);String realURL = buildRealURL(domain, soulContext, exchange);exchange.getAttributes().put(Constants.HTTP_URL, realURL);// set the http timeoutexchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());exchange.getAttributes().put(Constants.HTTP_RETRY, ruleHandle.getRetry());return chain.execute(exchange);

上面的代码只是解析了需要分发的url设置到exange的上下文中,真正进行请求的代码还需要重新找......

通过对 Constants.HTTP_URL 进行引用查找,找到还有 WebClientPlugin(org.dromara.soul.plugin.httpclient.WebClientPlugin) 和 NettyHttpClientPlugin(org.dromara.soul.plugin.httpclient.NettyHttpClientPlugin) 引用了这个常量

查看这两个类,发现都有进行HTTP请求发送和返回的操作,但 NettyHttpClientPlugin 的返回值不再进行chain调用,猜想请求会先走 WebClientPlugin, 再走 NettyHttpClientPlugin

在两个类中各打个断点,发送请求......

请求走了 WebClientPlugin 但没有走 NettyHttpClientPlugin,猜想有误。仔细读 org.dromara.soul.plugin.httpclient.WebClientPlugin#handleRequestBody 方法

private Mono<Void> handleRequestBody(final WebClient.RequestBodySpec requestBodySpec,final ServerWebExchange exchange,final long timeout,final int retryTimes,final SoulPluginChain chain) {return requestBodySpec.headers(httpHeaders -> {httpHeaders.addAll(exchange.getRequest().getHeaders());httpHeaders.remove(HttpHeaders.HOST);}).contentType(buildMediaType(exchange)).body(BodyInserters.fromDataBuffers(exchange.getRequest().getBody())).exchange() // 这里定义了交互的行为.doOnError(e -> log.error(e.getMessage())).timeout(Duration.ofMillis(timeout)).retryWhen(Retry.onlyIf(x -> x.exception() instanceof ConnectTimeoutException).retryMax(retryTimes).backoff(Backoff.exponential(Duration.ofMillis(200), Duration.ofSeconds(20), 2, true))).flatMap(e -> doNext(e, exchange, chain));}

可以看到, 在这个方法中就进行了和本地服务完成交互。

带着问题读源码-soul(2021-01-14)相关推荐

  1. 带着问题读源码-soul(2021-01-16)

    ### 带着问题读源码系列之Dubbo插件 像往常一样启动 [soul-admin] 和 [soul-bootstrap] . 因为dubbo需要依赖zookeeper, 需要需要启动一个监听在 lo ...

  2. 带着问题读源码-soul(2021-01-15)

    带着问题读源码系列-soul的本地服务筛选 在上一期中,了解到soul的http请求是通过dividePlugin插件完成对本地服务的筛选. 总体来说,可以分为两步: 1. 选出符合调用要求的服务列表 ...

  3. 夜读源码,带你探究 Go 语言的iota

    Go 语言的 iota 怎么说呢,感觉像枚举,又有点不像枚举,它的底层是什么样的,用哪个姿势使用才算正规,今天转载一篇「Go夜读」社区上分享的文章,咱们一起学习下.Go 夜读,带你每页读源码~!  这 ...

  4. myisam怎么读_耗时半年,我成功“逆袭”,拿下美团offer(刷面试题+读源码+项目准备)...

    欢迎关注专栏[以架构赢天下]--每天持续分享Java相关知识点 以架构赢天下​zhuanlan.zhihu.com 以架构赢天下--持续分享Java相关知识点 每篇文章首发此专栏 欢迎各路Java程序 ...

  5. 微信读书vscode插件_跟我一起读源码 – 如何阅读开源代码

    阅读是最好的老师 在学习和提升编程技术的时候,通过阅读高质量的源码,来学习专家写的高质量的代码,是一种非常有效的提升自我的方式.程序员群体是一群乐于分享的群体,因此在互联网上有大量的高质量开源项目,阅 ...

  6. 手把手带你阅读Mybatis源码(三)缓存篇

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 前言 大家好,这一篇文章是MyBatis系列的最后一篇文章,前面两篇文章:手把手带你阅读M ...

  7. (建议收藏)第一人称视角带你走进 Vue 源码世界

    点击上方关注 前端技术江湖,一起学习,天天进步 前言 本文不引战,成熟的人应该脱离框架的范畴,而不是纠结谁更好或者谁更不好.有道是黑猫白猫,抓到老鼠就是好猫. 所以本文会带大家读源码.简单易懂,大佬小 ...

  8. 「建议收藏」第一人称视角带你走进 Vue 源码世界

    前言 本文不引战,成熟的人应该脱离框架的范畴,而不是纠结谁更好或者谁更不好.有道是黑猫白猫,抓到老鼠就是好猫. 所以本文会带大家读源码.简单易懂,大佬小白都能看明白.并收获益处. 从 new 一个 V ...

  9. 京东CTO的笔记23种设计模式和5大读源码方法...!网友:这次稳了...

    大家都知道源码框架有23个设计模式,但是我们大多停留在概念层面,真实开发中很少应用到,也不知道如何落地!!!那有没有办法解决了? 我整理了 Mybatis 和 Spring 源码中使用了大量的设计模式 ...

最新文章

  1. R语言dataframe数据列中的缺失值NA的个数统计实战:特定数据列的NA值统计、所有特征的NA值统计
  2. 深度剖析WinPcap之(九)——数据包的发送过程(12)
  3. linkedin databus介绍——监听数据库变化,有新数据到来时通知其他消费者app,新数据存在内存里,多份快照...
  4. C#如何把日期转成YYYYMMDDHHMMSSFFF的精确到毫秒的格式?
  5. 深度学习利器:TensorFlow与NLP模型
  6. iOS --- DIY文件名批量修改
  7. Javascript基础系列之(六)循环语句(do while循环)
  8. 【Ajax Servlet JSP MySQL】Ajax实现省份地区选择:三级联动
  9. tableau三轴合并_《Tableau数据可视化实战》——1.12节合并不同数据源-阿里云开发者社区...
  10. fcc认证_介绍fCC 100:我们对2019年杰出贡献者的年度总结
  11. Unix 多进程编程
  12. 【Kafka】Kafka BrokerEndPointNotAvailableException: End point with security protocol PLAINTEXT not
  13. 千牛机器人回复词库_智能聊天机器人 ai机器人电销-
  14. Java使用循环创建多个线程
  15. RN对接京东支付sdk(Android)
  16. 软件测试流程--->测试报告的编写
  17. 初一网络计算机基础知识,初一计算机基础知识复习题da.docx
  18. H264码流中NALU sps pps IDR帧的理解
  19. 爱快 Open v服务端 全局推送路由器命令
  20. 安兔兔电脑ssd测试软件,安兔兔SSD测试软件测评,威钰战国NVMe SSD

热门文章

  1. GUI上半段学习总结
  2. 计算机云算力,分布式计算机云计算处理方法与流程
  3. Android 分割线
  4. Kmdtut 10---注册表
  5. BIGEMAPapp导入文件方式
  6. 移动DRM技术分析与应用策略
  7. 用软笔,写慢字:键盘时代如何拯救书法?
  8. 海外媒体发稿:国外最受欢迎的主流新闻媒体网站有哪些?
  9. 剑指offer T46把数字翻译成字符串
  10. 如何解决删除文件时显示已经被另一程序占用打开的问题