JAVA拾遗关于SPI机制
原文:https://www.cnkirito.moe/spi/
一、实现一个自定义的SPI
1.项目结构
- invoker是用来测试的主项目
- interface是针对厂商和插件商定义的接口项目,只提供接口,不提供实现
- good-printer,bad-printer分别是两个厂商对interface的不同实现,所以他们会依赖于interface项目
主要实现的是,在不改变invoker代码,只更改依赖的前提下,切换interface的实现厂商
2.interface模块
com.spi.Printer
public interface Printer { void print();
}
interface只定义一个接口,不提供实现。规范的制定方一般都是比较牛叉的存在,这些接口通常位于java,javax前缀的包中,这里的printer只是模拟的一个规范接口。
3.good-printer模块
3.1 good-printerpom.xml
<dependencies> <dependency>
<groupId>com.lara</groupId>
<artifactId>interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
规范的具体实现类必然要依赖规范接口
3.2 com.spi.GoodPrinter
public class GoodPrinter implements Printer { public void print() {
System.out.println("you are good");
}
}
作为printer规范接口的实现一
3.3 在resource下添加services文件
每一个SPI接口都需要在自己项目的静态资源目录中声明一个services文件,文件名为实现规范接口的类名全路径,此例中便是 com.spi.Printer,文件中的内同则为实现类的全路径,此例中便是com.spi.GoodPrinter.
这样一个厂商的实现便完成了。
4.bad-printer模块
和上述的good-printer的实现一样
4.1 bad-printerpom.xml
<dependencies> <dependency>
<groupId>com.lara</groupId>
<artifactId>interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
4.2com.spi.BadPrinter
public class BadPrinter implements Printer { public void print() {
System.out.println("you are bad");
}
}
4.3在resource下添加services文件
5.invoker模块
这里的invoker便是我们自己的项目了。如果一开始我们想使用厂商bad-printer的Printer实现,是需要将其的依赖引入
<dependencies> <dependency>
<groupId>com.lara</groupId>
<artifactId>interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.lara</groupId>
<artifactId>bad-printer</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
5.1编写调用主类
public class MainClass { public static void main(String[] args) {
ServiceLoader<Printer> printLoaders = ServiceLoader.load(Printer.class);
for (Printer printer : printLoaders){
printer.print();
}
}
}
ServiceLoader是java.util提个的用于加载固定类路径下文件的一个加载器,正式它加载了对应接口声明的实现类。
5.2打印结果1
在后续的方案中,想替换厂商的Printer实现,只需要将依赖更换,调用主类无需变更代码,符合开闭原则。
5.3打印结果2
以上是 JAVA拾遗关于SPI机制 的全部内容, 来源链接: utcz.com/z/517854.html