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


简介

    综合前面所分析的插件处理流程相关知识,此次我们来编写自定义的插件:统计请求在插件链中的经历时长

编写准备

    首先我们先探究一下,一个Plugin是如何加载到上篇文章分析中的 plugins 中的,plugins 代码如下:

    我们查看下 plugins 的值,发现global也在里面,也就是所有的plugin都是在里面

public class SoulConfiguration {@Bean("webHandler")public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {List<SoulPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);// global plugin 也在里面final List<SoulPlugin> soulPlugins = pluginList.stream().sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());soulPlugins.forEach(soulPlugin -> log.info("load plugin:[{}] [{}]", soulPlugin.named(), soulPlugin.getClass().getName()));return new SoulWebHandler(soulPlugins);}
}

    在上面的调用栈已经中断了,一直翻不到什么有用的东西,换换思路,我们在 globalPlugin 构造函数上打上断点,重启

    启动后,果然调用栈更新,我们看看调用栈,看到上面的 SoulConfiguration 调用是在 globalPlugin 之前,所以没啥有用的东西

    我们查看下 globalPlugin 构造函数的调用触发上一节,发现是下面这个: GlobalPluginConfiguration

@Configuration
@ConditionalOnClass(GlobalPlugin.class)
public class GlobalPluginConfiguration {@Beanpublic SoulPlugin globalPlugin(final SoulContextBuilder soulContextBuilder) {return new GlobalPlugin(soulContextBuilder);}
}

    我们仔细看看这个类,它是Spring Configuration,生成bean后注入进去,后面Spring会自己进行操作装配之类

    我们注意到这个bean返回的是 SoulPlugin ,还记得我们前面文章分析的所有Plugin都是继承于这个的,所以 List 就会自动装配到所有的 plugin。这个细节我也不是很懂,Spring还是不够熟系,后面需要补一补

    但看到这,我们大致思路就有了:

  • 1.写一个自定义插件
  • 2.写一个自定义插件的Spring配置,注入进去

自定义插件编写

    首先说明下,插件的编写应该遵循Soul网关的规范,还是应该写到Soul-Plugin这个模块中,但我们只是试验验证,就随意一点,直接写在Soul-Bootstrap中

    PS:时间有点小紧张,研究规范编写也伤时间,下次一定

工程结构

    此次需要编写两个文件:

  • 自定义插件:TimeRecordPlugin
  • 自定义插件配置:TimeRecordConfiguration

    目录结构大致如下:直接在源码的Soul-Bootstrap模块下

├─src
│  ├─main
│  │  ├─java
│  │  │  └─org
│  │  │      └─dromara
│  │  │          └─soul
│  │  │              └─bootstrap
│  │  │                  ├─configuration : 放入自定义插件配置
│  │  │                  ├─filter
│  │  │                  └─plugin :放入自定义插件
│  │  └─resources

自定义插件编写

    首先继承 SoulPlugin ,这样能正常注入到datalist中

    然后编写相应的处理函数,在处理函数中,我们在请求第一次进入到插件的时候,在exchange中放入当前的系统时间

    模仿 WebClientResponsePlugin ,在plugin链执行返回后,我们取出之前的系统时间,用当前系统时间减去,得到请求在plugin链中的经历时长

    order方面需要注意, globalPlugin的order为0,通过前面文章的分析,它进行的操作也不小,我们这个插件得在它前面,那我们的order就设置为-1

    这样,一个自定义插件就写好了,大致代码如下:

import lombok.extern.slf4j.Slf4j;
import org.dromara.soul.plugin.api.SoulPlugin;
import org.dromara.soul.plugin.api.SoulPluginChain;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Slf4j
public class TimeRecordPlugin implements SoulPlugin {private final String TIME_RECORD = "time_record";@Overridepublic Mono<Void> execute(ServerWebExchange exchange, SoulPluginChain chain) {exchange.getAttributes().put(TIME_RECORD, System.currentTimeMillis());return chain.execute(exchange).then(Mono.defer(() -> {Long startTime = exchange.getAttribute(TIME_RECORD);if (startTime == null) {log.info("Get start time error");return Mono.empty();}long timeRecord = System.currentTimeMillis() - startTime;log.info("Plugin time record: " + timeRecord + " ms");return Mono.empty();}));}@Overridepublic int getOrder() {return -1;}
}

自定义插件配置

    灰常的简单,我们不需要任何东西,所以没有啥参数传入,直接new一个返回即可,代码如下:

import org.dromara.soul.bootstrap.plugin.TimeRecordPlugin;
import org.dromara.soul.plugin.api.SoulPlugin;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@ConditionalOnClass(TimeRecordPlugin.class)
public class TimeRecordConfiguration {@Beanpublic SoulPlugin timeRecordPlugin() {return new TimeRecordPlugin();}
}

运行测试

    我们把Soul-admin、Soul-Bootstrap、Soul-Example-Http给启动起来

    访问:http://127.0.0.1:9195/http/order/findById?id=1111

    查看日志,看到明显自定义插件的日志打印,NICE!

o.d.s.plugin.httpclient.WebClientPlugin  : The request urlPath is http://192.168.101.104:8188/order/findById?id=1111, retryTimes is 0
o.d.s.bootstrap.plugin.TimeRecordPlugin  : Plugin time record: 9 ms
o.d.soul.plugin.base.AbstractSoulPlugin  : resilience4j selector success match , selector name :http_limiter
o.d.soul.plugin.base.AbstractSoulPlugin  : resilience4j rule success match , rule name :http_limiter
o.d.soul.plugin.base.AbstractSoulPlugin  : divide selector success match , selector name :/http
o.d.soul.plugin.base.AbstractSoulPlugin  : divide rule success match , rule name :/http/order/findById
o.d.s.plugin.httpclient.WebClientPlugin  : The request urlPath is http://192.168.101.104:8188/order/findById?id=1111, retryTimes is 0
o.d.s.bootstrap.plugin.TimeRecordPlugin  : Plugin time record: 10 ms

总结

    Soul网关的主要处理分析基本快结束了,下篇写一个总结就准备开始分析另外一个重要的模块:数据同步

    此篇的自定义插件编写还是比较简单,没有涉及到选择器和规则,但想做类似Divide之类的插件也不是不可以,那就直接把URI判断规则写死

    因为请求的所有数据都可以获取的,不用到后台只是规则不能动态变化而已

    有兴趣的老哥可以尝试写一下,还是挺有意思的,哈哈

Soul网关源码分析文章列表

Github

  • Soul源码阅读(一) 概览

  • Soul源码阅读(二)代码初步运行

  • Soul源码阅读(三)HTTP请求处理概览

  • Soul网关源码阅读(四)Dubbo请求概览

  • Soul网关源码阅读(五)请求类型探索

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

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

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

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

  • Soul网关源码阅读番外篇(一) HTTP参数请求错误

掘金

  • Soul网关源码阅读(一) 概览

  • Soul网关源码阅读(二)代码初步运行

  • Soul网关源码阅读(三)请求处理概览

  • Soul网关源码阅读(四)Dubbo请求概览

  • Soul网关源码阅读(五)请求类型探索

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

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

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

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

  • Soul网关源码阅读番外篇(一) HTTP参数请求错误

Soul网关源码阅读(十)自定义简单插件编写相关推荐

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

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

  2. Soul网关源码阅读19-解析sign插件

    sign插件是 soul网关自带的,用来对请求进行签名认证的插件,下面来解析一下sign插件. 一.环境搭建 soul-admin 开启 sign 插件:系统管理 --> 插件管理 soul-b ...

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

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

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

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

  5. Soul网关源码阅读番外篇(一) HTTP参数请求错误

    Soul网关源码阅读番外篇(一) HTTP参数请求错误 共同作者:石立 萧 * 简介     在Soul网关2.2.1版本源码阅读中,遇到了HTTP请求加上参数返回404的错误,此篇文章基于此进行探索 ...

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

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

  7. Soul网关源码阅读(六)请求类型探索

    Soul网关源码阅读(六)请求类型探索 简介     在上几篇文章中分析了请求的处理流程,HTTP和RPC请求处理是互斥的,通过请求类型来判断,这篇文章来探索下请求类型的前世今生 源码分析     通 ...

  8. Soul 网关源码阅读(四)Dubbo请求概览

    Soul 网关源码阅读(四)Dubbo请求概览 简介     本次启动一个dubbo服务示例,初步探索Soul网关源码的Dubbo请求处理流程 示例运行 环境配置     在Soul源码clone下来 ...

  9. Soul 网关源码阅读(二)代码初步运行

    Soul 源码阅读(二)代码初步运行 简介     基于上篇:Soul 源码阅读(一) 概览,这部分跑一下Soul网关的示例 过程记录     现在我们可以根据地图,稍微探索一下周边,摸一摸      ...

最新文章

  1. python编程分析了一下高考那些事,发现了两个之最,原来是这样
  2. 中国呼吸道防护劳保用品市场投资效益与销售前景调研报告2022年
  3. 使用yarn安装quasar,quasar创建新项目 出错error eslint
  4. Cocos2d-x 3.2 学习笔记(四)学习打包Android平台APK!
  5. 复制密钥文件到另一台服务器,使用所有ssh密钥从第三台服务器在两台服务器之间远程复制...
  6. The NVIDIA driver on your system is too old (found version 10000). Please update your GPU driver by
  7. java编程 队列_5.1、顺序队列(java实现)
  8. 宝塔修改Nginx服务器类型,宝塔面板nginx更改日志格式的方法
  9. 华为P40 Pro相机高清细节图曝光:潜望式长焦镜头抢眼
  10. throw与throws
  11. html怎么给表格加a链接地址,html基础02-图片标签、绝/相对地址、表格的属性、链接的属性及链接的分类、name定义锚点的名称、编码...
  12. CentOS 7下Gitlab安装和迁移
  13. 【李宏毅2020 ML/DL】P26-33 Explainable ML
  14. matlab画x的1 3次方图像,Y=X的3次方的图像)
  15. 三月月赛 1005 wuli通通和doge(细节处理)
  16. Swiper实现手风琴式的图片展示
  17. python sklearn metrics,在Python中sklearn.metrics.mean_squared_error越大越好(否定)?
  18. 如何查看笔记本电脑的型号?
  19. 【违规举报】违规举报方法步骤
  20. Unity3D之矩阵运用

热门文章

  1. Can't use Subversion command line client:svn
  2. maven项目动态替换配置中的值
  3. 结组开发项目(TD学生助手)
  4. 关于解决Server Tomcat v9.0 Server at localhost failed to start的问题
  5. 【报告分享】2021中国人才趋势报告.pdf(附下载链接)
  6. 全球首发!计算机视觉Polygon Mesh Processing总结9——Triangle-Based Remeshing
  7. Airbnb搜索:深度学习排序算法如何进化?
  8. php 换一换 功能,vue换一换功能原型
  9. Java多线程同步屏障计算_Java多线程之CountDownLatch和CyclicBarrier同步屏障的使用
  10. 扫掠曲面二条引导线_说说国策下的三四线城市与会展