前两篇文章都在了解 HTTP 接口是怎么被 soul 网关代理的,先是新建了一个提供 http 接口的项目,然后引入 soul 的 starter 依赖去完成 http 接口的注册,然后从源码上去解读了项目启动过程中 http 接口信息注册到 soul-admin 模块。

但是这依然不是完整的流程,因为 soul-admin 服务开放的端口是 9095,真实的 http 服务端口是 8080,但是我们使用 soul 网关去访问接口却是使用的 9195,也就是说,http 的接口信息除了注册到了 soul-admin,还传递给了 soul 网关。

所以又回到了上一次留下的问题:配置 soul 网关的地址明明只是端口为 9095 的 soul-admin,为啥最后代理的端口是 9195?

但是从我们自己新建的项目里来看,是没有任何有关于 soul 网关的配置信息的,只有直接关联了 soul-admin。那么可以猜测下,是不是 soul-admin 背着我们干了这些事?

soul-admin 偷偷干了啥

还是老规矩,一条线走到黑,暂时只关注 http 接口相关的部分。

先从配置文件开始,里面需要关注的配置内容也不多,数据库就可以忽略了。另外一个重要的就是数据同步这部分内容了。就先了解默认的 websocket 同步方式吧。

  1. soul:
  2. sync:
  3. websocket:
  4. enabled: true

配置内容找到了,接下来就是找配置使用的地方了。

可以在 org.dromara.soul.admin.config.DataSyncConfiguration 配置类里面找到这样的代码。

  1. @Configuration
  2. public class DataSyncConfiguration {
  3. /**
  4. * The WebsocketListener(default strategy).
  5. */
  6. @Configuration
  7. @ConditionalOnProperty(name = "soul.sync.websocket.enabled", havingValue = "true", matchIfMissing = true)
  8. @EnableConfigurationProperties(WebsocketSyncProperties.class)
  9. static class WebsocketListener {
  10. /**
  11. * Config event listener data changed listener.
  12. *
  13. * @return the data changed listener
  14. */
  15. @Bean
  16. @ConditionalOnMissingBean(WebsocketDataChangedListener.class)
  17. public DataChangedListener websocketDataChangedListener() {
  18. return new WebsocketDataChangedListener();
  19. }
  20. /**
  21. * Websocket collector websocket collector.
  22. *
  23. * @return the websocket collector
  24. */
  25. @Bean
  26. @ConditionalOnMissingBean(WebsocketCollector.class)
  27. public WebsocketCollector websocketCollector() {
  28. return new WebsocketCollector();
  29. }
  30. /**
  31. * Server endpoint exporter server endpoint exporter.
  32. *
  33. * @return the server endpoint exporter
  34. */
  35. @Bean
  36. @ConditionalOnMissingBean(ServerEndpointExporter.class)
  37. public ServerEndpointExporter serverEndpointExporter() {
  38. return new ServerEndpointExporter();
  39. }
  40. }
  41. }

可以看到这个类只会在配置了上面的信息之后才会执行加载。

里面重要的有两个点:

  1. 使用 WebSocket 开启了一个 socket 服务
  2. 将会实例化一个 WebsocketDataChangedListener 实例,看名字大概就能猜到是当监听到数据有变化时候的处理过程

对于第一点,使用了 spring-boot-starter-websocket 依赖去开启了一个 web socket 的 endpoint,可以跟 web 服务共用一个端口 9095。

既然是提供了 web socket 的服务,那么肯定有对应的 client 端来连接它吧,那会是谁呢?

回到开头的问题,我们从自己的 http 服务一路追寻到了 soul-admin 模块,至今都没有跟 soul-bootstrap 打过交道(无论是自己的 http 服务,还是当前的 soul-admin 模块),但偏偏网关的代理是由 soul-bootstrap 去完成的。

结合上面的 web socket 服务,答案也就显而易见了吧。 没错,soul-admin 通过提供了 web socket 服务,去充当了一个中间人的角色。

我们自己的 http 服务注册接口信息到 soul-admin,soul-admin 提供 web socket 服务,soul-bootstrap 主动建立连接到 soul-admin,终于——三者的联系找到了。

明白了这一点,那就可以去 soul-bootstrap 找找有没有 soul-admin 模块的 web socket 服务配置了。配置内容如下:

  1. soul :
  2. file:
  3. enabled: true
  4. corss:
  5. enabled: true
  6. dubbo :
  7. parameter: multi
  8. sync:
  9. websocket :
  10. urls: ws://localhost:9095/websocket

总结

所以到目前为止,我们已经可以解答开头的问题了,接口的数据先是传递到了 soul-admin,然后 soul-bootstrap 主动跟 soul-admin 的 web socket 服务连接获取数据,这样 soul-bootstrap 也就知道了接口的地址,从而可以对外提供接口代理的服务了。

但是,这只是从代码上找到了它们三个的联系,加上自己的逻辑证明了这个过程,那么接口数据传递具体是怎么实现的呢?

我们下一篇文章继续深入探究数据是怎么通过 soul-admin 到 soul-bootstap 网关的。