原因
- 在一开始使用spring cloud插件的时候,调用网关没有得到请求,一直返回:Can not find url, please check your configuration!
先说原因,是因为在bootstrap中,没有打开spring cloud的相关依赖导致的,具体分析如下。
分析
首先,我们通过网关访问我们的项目,我们知道soul是集成插件达到各种功能的,那么,我们就不用去找soul的入口,可以先去找插件,
- 插件的类依赖关系就像下面这样
- 可以看到,顶层是接口,接口的唯一直接实现,是这个抽象类AbstractSoulPlugin,而SpringCloudPlugin继承抽象类做具体的实现。
- 我们可以看下,抽象类里面都是什么东东。
- 类里面方法太多了,就贴最核心的2个方法吧,一个protected的抽象方法doExecute,一个public的方法execute,注意看抽象方法的注释,说明这是模版方法,子类继承的时候在里面实现自己的逻辑,非常标准的模版模式运用(模版模式:简单来说,就是对外提供一个抽象方法,交给子类实现,这个抽象方法的调用,则在抽象类的骨架方法里面调用,上图的execute方法,就是骨架方法,还不清楚,就去查查资料吧)。
- 其实还有2个直接实现接口的类WebClientPlugin,GlobalPlugin
- 先说WebClientPlugin,为啥不继承抽象类,要单独实现呢,个人分析是因为这其实是soul在进行http调用时的核心插件,所有的http调用,都是由这个插件来完成,是soul的默认插件,也许细心的你会发现,在soul-admin中的web控制台中,这个插件不在插件列表里,你不能操作它,而继承了抽象类的插件们,是对客户端提供的可选插件,虽然所有的插件,都在一个插件链里面,但是他们的价值不同,所以,在具体实现上区别开了。
- 而GlobalPlugin插件,见名知意,是整个soul插件的基础,看看GlobalPlugin的关键方法。
1 | @Override |
- 来看看execute这个骨架方法具体都干什么
1 | // ServerWebExchange是webflux的请求处理器 |
既然说了插件链,那就应该看看,插件链在哪,怎么生成的,链的顺序是怎样的
- 在模版方法处debug,逆向寻找,最终找到了插件链定义的地方:SoulWebHandler
- 查看构造方法的调用,找到了插件链生成的地方:SoulConfiguration
- 通过Spring的bean属性注入,来构造的插件链,Spring在执行该方法的时候,会根据方法参数,将所有实现了SoulPlugin接口并且委托给Spring管理的bean都封装后传入。
- 注意看,插件链在构造的时候,是排了序的,为什么要排序,要归根于插件具体的作用不同,有的插件是初始化的,有的是参数处理的,有的是实际执行的,举个例子,刚刚说了,soul中进行http调用实际上用的是wenClientPlugin插件来执行的,那么,那些要使用http调用的插件,比如divide插件,不是重复了么,那我们来看看divide插件里面,干了什么。
1 | protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) { |
- 可以看到,就是设置了下http的url跟一些相关参数,前面我们说了,soul插件链的处理,使用了模版模式做了一层抽象设计,http的调用,用的是souWebClient插件,这就要看看souWebClient的模版方法写的啥了。
1 | @Override |
- 所以,已经可以肯定soul中需要使用http进行调用的可选插件,都只是进行了http参数的设置,通过soulContext进行传递,交给webClient插件进行调用。也就能说通,为什么插件链生成的时候要排序了,如果不进行排序,webClient插件链在其他插件之前被执行了,那就GG了,类似的,基于dubbo, sofa协议的rpc调用,也会在实际执行之前,先进行请求的构建,只是具体实现稍有不同。具体插件们的顺序,在**PluginEnum中定义了。**
- 还有一个插件与WebClientPlugin一样比较特殊,GlobalPlugin,它是初始化插件
- 前面说了插件链的定义、生成,插件链的顺序,也说了具体的插件是通过Spring注入的,那么这些具体的插件bean在哪里交给Spring托管的呢
每一个插件,都提供了对应的starter来进行插件的实例化,从而可以在构造soulWebHandler时拿到插件。
总结
- 至此,http插件的一个调用过程就说完了,原因就如一开始所说,spring cloud也是通过http来进行调用,pom没有加入Spring cloud相关的依赖,导致soul在创建webHandler的时候,没有加载到spring cloud插件,也就没有spring cloud相关的配置,自然也就调用不到实际的url了。
- 最后是插件调用链的图。