欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Soul网关源码分析-16期(未完)

程序员文章站 2022-06-03 20:23:01
...


SOUL 中 SPI 的使用


在之前分析 divide 插件的负载均衡策略时, 有看到过一行代码:

DivideUpstream divideUpstream = LoadBalanceUtils.selector(upstreamList, ruleHandle.getLoadBalance(), ip);

当时很简单的略过了它的实现, 它的作用很容易分析, 调用一个看似工具类的方法, 传入多个节点组成的集群, 返回一个节点. 这是一个负载均衡器.


但是细节却非常多, 最重要的一点是使用 SPI 来选择具体的实现类. 看看这个方法的代码:

public class LoadBalanceUtils {

  public static DivideUpstream selector(final List<DivideUpstream> upstreamList, final String algorithm, final String ip) {
    // 调用自定义的 SPI 得到一个子类
    LoadBalance loadBalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getJoin(algorithm);
    return loadBalance.select(upstreamList, ip);
  }
}

后面的是调用具体子类的 select() 方法, 根据子类的不同实现, 最终会表现出各种形式. 目前的子类实现有:

  • HashLoadBalance
  • RandomLoadBalance
  • RoundRobinLoadBalance

关键就在于 ExtensionLoader.getExtensionLoader(LoadBalance.class).getJoin(algorithm); 这行.


在研究它之前, 我们先不妨研究下 Java 提供的 SPI 机制.




Java SPI


<<高可用可伸缩微服务架构>> 第3章 Apache Dubbo 框架的原理与实现 中有这样的一句定义.

SPI 全称为 Service Provider Interface, 是 JDK 内置的一种服务提供发现功能, 一种动态替换发现的机制. 举个例子, 要想在运行时动态地给一个接口添加实现, 只需要添加一个实现即可.


书中也有个非常形象的脑图, 展示了 SPI 的使用:

JavaSPI
设置META-INF目录
META-INF/services
放到classPath下面
META-INF下面放置配置文件
文件名是接口全路径名
文件内部是要实现的接口实现类
文件是UTF-8编码
如何使用
ServiceLoad.load

也就是说在我们代码中的实现里, 无需去写入一个 Factory 工厂, 用 MAP 去包装一些子类, 最终返回的类型是父接口. 只需要定义好资源文件, 让父接口与它的子类在文件中写明, 即可通过设置好的方式拿到所有定义的子类对象:

ServiceLoader<Interface> loaders = ServiceLoader.load(Interface.class)
for(Interface interface : loaders){
	System.out.println(interface.toString());
}

这种方式相比与普通的工厂模式, 肯定是更符合开闭原则, 新加入一个子类不用去修改工厂方法, 而是编辑资源文件.

相关标签: java 网关