我叫Spi,新成员

自我介绍

Spi,Service Provider Interface,是java提供的一套用来被第三方实现或扩展的API,它可以用来启用框架扩展或替换相应的组件。简单来说就是我提供标准,你按照我的标准提供实现就可以了,当然了,这个实现可以是可以有多个,你想选择哪个都可以,不过前提是你要知道所有的实现才能选择,这操作属于java中的策略模式,而所有的实现都被放在一个配置文件中,所以Spi基本上就是一个接口 + 策略模式 + 配置文件组合而成的动态加载机制。在面向对象的设计里,模块之间基于接口编程,模块之间不对实现类硬编码,在不同的场景下需要动态的指明实现类,这就需要一个服务发现的机制,Spi提供这样子的一个机制,为某个接口寻找服务实现的机制,将硬编码移到程序之外,也就是配置文件中,Spi的核心思想就是解耦

模拟Spi

既然是标准,那么肯定有一些必须要遵守的规范:

  1. 定义服务接口与服务接口的实现类,若是jar包则要在jar包的META-INF/services目录下创建一个以接口全限定名为文件名的文本文件,该文本文件的内容即服务接口实现类的全限定名
  2. 该jar包记得加入到classpath中。
  3. 服务接口的实现类必须有一个不带参数的构造方法,即默认的构造方法。

接下来看几个截图,具体的代码实现已经上传到github上了,有兴趣的读者可以看看,菜鸟级别的水平不要见怪!

Spi例子-1

请注意,创建META-INF/service目录后最好看一下目录结构,META-INF是一个目录,而service是它的子目录,这不是只有一层目录,当时就被自己给坑了。

Spi例子-2

看了以上的内容咱们顺便在说下Spi的优缺点,不对,优点就是一开始说的解耦,将业务代码分离,简单说下缺点吧。看到上面的截图中采用的是ServiceLoader类来加载实现类,源码当中采用的是懒加载的方式,只有当我们去遍历配置文件中的实现类时才会一一实例化,缺点很明显,只能通过遍历的方式去获取每个实现类,若你不想用某个实现类,它最终还是会被实例化,这势必造成了资源的浪费,没有提供通过传入某个参数来获取到指定的实现类,不够灵活。

总结

网上有人说很多框架当中使用了Spi机制,比如JDBC加载不同的类型数据库的驱动、不同的日志实现类、Dubbo,虽然这些我都没有看过,但解耦是每个程序都需要的,这也奠定了Spi的重要性。Spi的缺点很明显,可以在它的基础上在包装一层,这部分例子我从其他地方拷贝了过来,挺实用的,而正好是后期完善的,所以上面的截图中并没有显示这些内容,不过我已经放到了github上了,有兴趣可以看看。最后加油自己,加油每一个人。

源码下载

posted @ 2020-12-21 20:45  zliawk  阅读(70)  评论(0)    收藏  举报