在开发java组件时,一个功能组件往往需要支持多种规范,在客户端调用时需要根据不同情况,进行不同的服务调用。例如:客户端于服务端之间进行数据交互,数据交互协议有1.0、2.0、3.0。。。在组件开发时就需要至少开发出三个服务分别对应每种需求。
客户端使用组件时,需要根据自身情况调用不同协议版本的服务。
方案一:使用配置文件,通过外部挂载一个配置文件,客户端读取配置文件,根据配置类型调用组件的服务。
方案二:使用SPI。不需要外挂配置文件,通过修改jar包的META-INF/services/全路径类型的文件(内容为需要使用的服务的全路径类名)的方式来实现。
第一种方案参考:springBoot 配置项外提结合容器化_任庆 的博客-CSDN博客
重点说一下第二种方式。JDK6开始支持 SPI(Service Provider Interface),提供服务的接口。能够通过配置jar包的方式指定调用哪个实现,从而降低了客户端和实现的耦合度。而且实现起来也很简便,如果是轻量级应用就很适合。
第一步,new一个java Project(为了方便运行,我创建了一个springboot的项目)
第二步,定义一个服务接口,也就是SPI指的那个接口:
- public interface Driver {
-
- void work();
- }
第三步,定义两个实现类:
- public class DriverA implements Driver {
-
- @Override
- public void work() {
- System.out.println("DriverA is working");
- }
-
- }
- public class DriverB implements Driver {
-
- @Override
- public void work() {
- System.out.println("DriverB is working");
- }
-
- }
第四步,通过SPI调用:
- @SpringBootApplication
- public class HttpserverApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(HttpserverApplication.class, args);
-
- // 主要是下面这段
- ServiceLoader
loadedDrivers = ServiceLoader.load(Driver.class); - Iterator
iterator = loadedDrivers.iterator(); - while(iterator.hasNext()) {
- Driver next = iterator.next();
- next.work();
- }
-
- }
-
- }
第五步,build成jar包运行,这次是没有指定实现类的,因此Services是空,没有输出
第六步,修改MEAT-INF/services/xxxx,重新运行
- 新建 com.yfgg.httpserver.spi.Driver
- com.yfgg.httpserver.spi.Driver中添加内容 com.yfgg.httpserver.spi.DriverB
-
- **** SPI路径和实现类的全路径以实际为准
可以看到,指定DriverB运行成功。
使用场景:客户端添加一些service选择逻辑,配合jar包的配置文件,灵活调用组件的实现。在JDBC连接上常见。