Java SPI全稱Service Provider Interface,是Java提供的一套用來被第三方實現或者擴展的API,它可以用來啟用框架擴展和替換組件。實際上是“基于接口的編程+策略模式+配置文件”組合實現的動態(tài)加載機制.
ServiceLoader的使用
操作步驟:
1、定義一個接口文件
2、寫出多個該接口文件的實現
3、在 src/main/resources/ 下建立 /META-INF/services 目錄, 新增一個以接口命名的文件 , 內容是要接口的實現類全路徑
4、使用ServiceLoader類 來獲取到這些實現的接口
先創(chuàng)建一個interface的module。

然后在其他的模塊實現這個接口,并在實現這個接口的module中創(chuàng)建一個resources文件夾,文件夾里建一個文件,文件名為(對應接口的全路徑 + 接口名),文件里面寫的內容則為其(實現類的全路徑+實現類名)。在操作過程中,遇到了一個坑,就是文件夾是兩級文件夾,我在操作的時候圖簡單,直接META-INF.services,結果導致通過ServiceLoader獲取實現類的時候,獲取為空。這里應該先創(chuàng)建一個文件夾,命名為META-INF,然后再在這個文件夾再創(chuàng)建一個文件夾,命名為services,雖然在AS上顯示仍然為META-INF.services,但是這是一個二級文件夾 ,而我那種做法只算以及文件夾。導致獲取不到文件里的內容。

然后創(chuàng)建一個help類,其具體的實現為:
public class ServiceHelper {
//針對一種接口多個實現類操作
public static <T> List<T> getServices(Class<T> interfaceClass){
ServiceLoader loader = ServiceLoader.load(interfaceClass);
Iterator iterator = loader.iterator();
List<T> list = new ArrayList<>();
while (iterator.hasNext()){
T t = (T) iterator.next();
if (t != null){
list.add(t);
}
}
return list;
}
//針對一個接口一個實現類操作
public static <T> T getService(Class<T> interfaceClass){
ServiceLoader loader = ServiceLoader.load(interfaceClass);
Iterator<T> iterator = loader.iterator();
if (iterator.hasNext()){
return (T) iterator.next();
}else {
return null;
}
}
}
然后在App模塊中調用,
AInterface aInterface = ServiceHelper.getService(AInterface.class);
Log.e("zzf",aInterface + "");
BInterface bInterface = ServiceHelper.getService(BInterface.class);
Log.e("zzf",aInterface.getname() +"------------" + bInterface.getname());


這種方法在平常組件化開發(fā)中非常便利,但是每次都需要到/META-INF/services 目錄建立文件,不能動態(tài)添加。因此采用Google的@AutoService,他可以幫我們在編譯的時候動態(tài)去生成這些東西。
ServiceLoader + @AutoService的使用
添加依賴:
implementation 'com.google.auto.service:auto-service:1.0'
annotationProcessor 'com.google.auto.service:auto-service:1.0'
接口module不需要變,我們只需要在實現類進行改變一下即可:
@AutoService(CInterface.class)
public class C2Impl implements CInterface {
@Override
public String getName() {
return "C2Impl";
}
}
只需要在具體的實現類上面加上一個@AutoService注解,參數則為接口的class類。
然后在App模塊中調用,
List<CInterface> list = ServiceHelper.getServices(CInterface.class);
for (CInterface cInterface:list){
Log.e("zzf",cInterface.getName());
}
ARouter
阿里的ARouter框架就是是借助了這種思想,它只需要我們的自己的接口繼承IProvider接口,
public interface BInterface extends IProvider {
String getname();
}
然后在B模塊實現接口
@Route(path = "/user/BInterface")
public BImpl implements BInterface{
@Override
public String getname() {
return "A2Impl";
}
}
然后在其他模塊通過ARouter注解獲取實例
@Autowired//(name = "/user/BInterface")
BImpl mBImpl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ARouter.getInstance().inject(this);
...