Soul源码阅读系列(二)Divide插件

今天体验的是Souldivide插件,它的主要作用是用于http的代理。在文章后面一节简单分析了divide插件的执行原理。

Divide插件使用案例

Soul官方在soul-examples模块提供了测试样例,其中的soul-examples-http模块演示的通http发起请求到soul网关,然后再到真实的服务。模块目录及配置信息如下:

soul.http是有关Soul的配置,adminUrlSoul的后台管理地址,port是业务系统的端口,contextPath是业务系统的请求路径。

在项目的pom文件中引入soul相关依赖,当前版本是2.2.1

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

在需要被代理的接口上使用注解@SoulSpringMvcClient@SoulSpringMvcClient注解会把当前接口注册到soul网关中。使用方式如下:

如果其他接口也想被网关代理,使用方式是一样的,在@SoulSpringMvcClient注解中,指定path即可。

参考之前的文章,启动Soul AdminSoul BootstrapSoul的后台管理地址,是一个SpringBoot项目,只需要修改一下数据库的地址就可以运行了。项目会自动创建对应的库和表。项目启动后的登录地址是http://localhost:9095/,用户名是admin,密码是123456。后台界面如下:

最后运行SoulTestHttpApplication,启动soul-examples-http项目。

当三个系统(本身的业务系统,Soul后台管理系统Soul Admin,Soul核心网关Soul Bootstrap)都启动成功后,就能够使用divide插件了。

发起一个Get请求: http://localhost:8188/order/findById?id=99 
得到的响应结果:
{
  "id": "99",
  "name": "hello world findById"
}

上面就是一个普通的http请求,直接请求业务系统的后端服务,现在通过Soul网关来访问该服务。

同样发起一个Get请求:http://localhost:9195/http/order/findById?id=99
得到的响应结果:
{
  "id": "99",
  "name": "hello world findById"
}

这个localhost:9195地址就是网关的地址,/http是业务系统在网关中的名称。那么,现在的请求就是先通过Soul网关,再由网关转发到实际的请求接口。

通过后台管理系统可以发现:主要模块有插件列表和系统管理,在插件列表中可以对各个插件进行管理,每个插件都可以添加多个选择器,每个选择器都可以添加多条规则。实际这就是Soul拦截URL后的匹配规则:插件->选择器->规则,这个后面再细说。

以上就是Soul作为一个网关起到转发的作用,这个功能模块对应的插件是divide插件。接下来,我们跟踪一下divide插件的源码,看看它的执行原理。

Divide插件执行原理

当我们第一次接触时,可能不知道它的执行逻辑在源代码的哪个位置,那怎么办呢?

答案是 ,如何猜测呢?我们想要查看的是divide插件,那就去插件模块soul-plugin看看。然后再找找有没有跟divide有关的,发现有一个soul-plugin-divide。进入这个模块里面,有一个DividePlugin类,它有doExecute()方法,那我们也能猜测它可能就是divide插件的执行逻辑。

有了上面的猜想,我们还需要进行验证,看看对不对,在doExecute()方法加上断点进行debug调试。将soul-bootstrap项目以debug模式进行重启,然后发起请求:

http://localhost:9195/http/order/findById?id=99

成功发起请求后,执行逻辑会在我们打断点的地方停住,那么证明我们的猜想是正确的(在这里可以再次体会到命名的重要性)。这个时候要注意观察IDEA编辑器提供的方法调用栈信息:

方法调用栈里面有很多方法,但是前面四个是soul中的方法调用,后面的与reactor编程模型有关,先暂时忽略它。在前面四个方法中,调用关系如下:

  • SoulWebHandler:它实现了WebHandler,重写了handle()方法,用于处理Soul网关中所有的请求。
  • DefaultSoulPluginChain:插件链执行类,以责任链的设计模式处理所有插件。
  • AbstractSoulPlugin:多个插件的父类,以模板方法设计模式实现各种插件类型。
  • DividePlugindivide插件,用于处理http请求。

分析到这里,就能够清楚的看到Soul网关处理一个http请求的过程,具体实现就在以上四个类及对应的方法中。实际的代码解析将在下一篇文章中进行分析,因为比较多,做好准备~

到这里,本篇文章就结束了,小结一下:本篇文章通过一个案例演示了http请求怎么接入到Soul网关中,以及Divide插件的执行原理。