1、Java SPI機制 ServiceLoader的基本使用
-
Java SPI 實際上是“基于接口的編程+策略模式+配置文件”組合實現(xiàn)的動態(tài)加載機制,
提供了通過interface尋找implement的方法。類似于IOC的思想,將裝配的控制權(quán)移到程序之外,從而實現(xiàn)解耦。
Java SPI機制 場景:比如兩個module,app依賴basic_live,但這時basic_live又用到了app模塊中的服務(wù)。
源碼GitHub
2、方式一
- 在調(diào)用module中創(chuàng)建一個接口文件ContentService
- 在具體實現(xiàn)的module中的main目錄(Java同級)下建立resources/META-INF/services/,因為ServiceLoader中會訪問到(查看ServiceLoader.PREFIX)
- 在services文件夾中創(chuàng)建文件,以接口全名命名
- 在具體實現(xiàn)的module中創(chuàng)建類來實現(xiàn)接口功能ContentServiceImpl,然后把全類名填到上面創(chuàng)建的文件中
3、方式二
在方式一中,不僅要創(chuàng)建各種路徑、文件,容易寫錯,所以Google發(fā)布了一個庫autoservice幫助大家
在具體實現(xiàn)module中添加依賴,kotlin的可以用kpt
implementation 'com.google.auto.service:auto-service:1.0.1' annotationProcessor 'com.google.auto.service:auto-service:1.0.1' kapt 'com.google.auto.service:auto-service:1.0.1'實現(xiàn)接口,并加上@AutoService
@AutoService(ContentService.class) public class ContentServiceImpl implements ContentService { @Override public String getTitle() { return "the title from app module"; } }
4、使用
在ServiceFactory中加了緩存,通過
ContentService service = ServiceFactory.getInstance().getService(ContentService.class)獲取public class ServiceFactory { private static class SingleTonHolder { private static final ServiceFactory INSTANCE = new ServiceFactory(); } public static ServiceFactory getInstance() { return SingleTonHolder.INSTANCE; } private final ArrayMap<Class, ServiceLoader> loaderMap = new ArrayMap<>(); private final ArrayMap<Class, Object> serviceMap = new ArrayMap<>(); private ServiceFactory() { } @Nullable public <T> T getService(Class<T> clazz) { Object o = serviceMap.get(clazz); if (o != null && isInterface(o.getClass(),clazz.getName())) { return (T) o; } ServiceLoader serviceLoader = loaderMap.get(clazz); if (serviceLoader == null) { serviceLoader = ServiceLoader.load(clazz); loaderMap.put(clazz, serviceLoader); } if (serviceLoader != null && serviceLoader.iterator().hasNext()) { T next = (T) serviceLoader.iterator().next(); serviceMap.put(clazz, next); return next; } return null; } public boolean isInterface(Class c, String szInterface) { Class[] face = c.getInterfaces(); for (Class aClass : face) { if (aClass.getName().equals(szInterface)) { return true; } else { Class[] face1 = aClass.getInterfaces(); for (Class value : face1) { if (value.getName().equals(szInterface)) { return true; } else if (isInterface(value, szInterface)) { return true; } } } } if (null != c.getSuperclass()) { return isInterface(c.getSuperclass(), szInterface); } return false; } }
