目录
前言
为了实现Android-模块化通信-需要一套简单实用的android spi机制。
一、spi是什么?
SPI即 Service Provider Interface
,它是为接口提供寻找实现服务类,类似IOC的思想。
二、ServiceLoader
java中的spi
, ServiceLoader
尤为重要, 抛开注解生成代码和Transform
注册
load
可以使用map
实现,需要Class<T> baseClass
,String servicePath
构建返回约束和访问参数register
项目经常需要一些全局唯一的Service
以及使用时创建Service
,注册参数有path 索引唯一路径
,interfaceClass 接口类
,obj 单实例/实例/惰性
·简单实现代码如下·
1.ExportTableLoader
/**
* 作用描述: 导出表加载程序接口
* 组件描述: #基础组件 #组件名 (子组件)
* 组件版本: v1
* 创建人 rentl
* 创建日期 2022/2/4 21:23
* 修改日期 2022/2/4 21:23
*/
public interface ExportTableLoader {
/**
* 输出
*
* @param exporter
* @implNote {@link ExportTable#initTables(cn.mashang.export_table_java.ExportTableLoader[])}
*/
void export(ExportTable.Exporter exporter);
}
2.ExportTable
/**
* 作用描述: 导出表
* 组件描述: #基础组件 #组件名 (子组件)
* 组件版本: v1
* 创建人 rentl
* 创建日期 2022/2/4 21:21
* 修改日期 2022/2/4 21:21
*/
public final class ExportTable {
/**
* 服务列表map
*/
final static Map<Class<?>, List<Object>> serviceListMap = new HashMap<>();
/**
* 新服务地图
*/
final static Map<String, Object> newServiceMap = new HashMap<>();
/**
* 单例服务图
*/
final static Map<String, Object> singletonServiceMap = new HashMap<>();
private static ExportTableLoader[] tables = null;
private static final ExportTable.Exporter exporter = new ExportTable.Exporter();
private ExportTable() {
}
public static void initTables(ExportTableLoader[] tables) {
ExportTable.tables = tables;
init();
}
public static Exporter getExporter() {
return exporter;
}
private static void init() {
if (tables == null) {
return;
}
for (ExportTableLoader table : tables) {
if (table == null) {
continue;
}
table.export(exporter);
}
}
/**
* 导出表 出口商
*/
public final static class Exporter {
Exporter() {
}
/**
* 将单个实例放入路线图
*
* @param path 索引唯一路径
* @param interfaceClass 接口类
* @param proxyObj 单实例代理对象
*/
private void putSingletonToRoadMap(final String path, @SuppressWarnings("rawtypes") final Class interfaceClass, final Object proxyObj) {
if (path == null || path.isEmpty()) {
throw new IllegalArgumentException("putSingleInstance args: path is null");
}
if (proxyObj == null) {
throw new IllegalArgumentException("putSingleInstance args: proxyObj is null");
}
if (singletonServiceMap.containsKey(path)) {
throw new UnsupportedOperationException("putSingleInstance args: path is exist");
}
if (singletonServiceMap.containsValue(proxyObj)) {
throw new UnsupportedOperationException("putSingleInstance args: proxyObj is exist");
}
singletonServiceMap.put(path, proxyObj);
//all
List<Object> objects = serviceListMap.get(interfaceClass);
//noinspection Java8MapApi
if (objects == null) {
objects = new ArrayList<>();
serviceListMap.put(interfaceClass, objects);
}
objects.add(proxyObj);
}
/**
* 设置单实例
*
* @param path 索引唯一路径
* @param interfaceClass 接口类
* @param obj 单实例
*/
public <T> void setSingleton(final String path, final Class<T> interfaceClass, final T obj) {
putSingletonToRoadMap(path, interfaceClass, obj);
}
/**
* 使用惰性设置单实例
*
* @param path 索引唯一路径
* @param interfaceClass 接口类
* @param obj 单实例
* @param <T> 泛型类
*/
public <T> void setSingletonByLazy(final String path, final Class<T> interfaceClass, final LazyLoader<T> obj) {
putSingletonToRoadMap(path, interfaceClass, obj);
}
/**
* 将新实例放入路线图 (全局)
*
* @param path 索引唯一路径
* @param interfaceClass 接口类
* @param proxyObj 单实例代理对象
*/
private void putNewInstanceToRoadMap(final String path, @SuppressWarnings("rawtypes") final Class interfaceClass, final Object proxyObj) {
if (path == null || path.isEmpty()) {
throw new IllegalArgumentException("setNewInstance args: path is null");
}
if (proxyObj == null) {
throw new IllegalArgumentException("setNewInstance args: proxyObj is null");
}
if (newServiceMap.containsKey(path)) {
throw new UnsupportedOperationException("setNewInstance args: path is exist");
}
if (newServiceMap.containsValue(proxyObj)) {
throw new UnsupportedOperationException("setNewInstance args: proxyObj is exist");
}
newServiceMap.put(path, proxyObj);
//all
List<Object> objects = serviceListMap.get(interfaceClass);
//noinspection Java8MapApi
if (objects == null) {
objects = new ArrayList<>();
serviceListMap.put(interfaceClass, objects);
}
objects.add(proxyObj);
}
/**
* 设置对象实例惰性创建(推荐)
*
* @param path 索引唯一路径
* @param interfaceClass 接口类
* @param obj 单实例
* @param <T> 泛型类
*/
public <T> void setNewInstanceByLazy(final String path, final Class<T> interfaceClass, final LazyLoader<T> obj) {
putNewInstanceToRoadMap(path, interfaceClass, obj);
}
/**
* 设置对象实例反射创建(不推荐)
*
* @param path 索引唯一路径
* @param interfaceClass 接口类
* @param implementClass 单实例
* @param <T> 泛型类
*/
public <T> void setNewInstanceClass(final String path, final Class<T> interfaceClass, final Class<T> implementClass) {
putNewInstanceToRoadMap(path, interfaceClass, implementClass);
}
}
}
3.LazyLoader
/**
* 作用描述: 懒加载程序
* 组件描述: #基础组件 #组件名 (子组件)
* 组件版本: v1
* 创建人 rentl
* 创建日期 2022/2/8 15:02
* 修改日期 2022/2/8 15:02
*/
public class LazyLoader<T> {
private final Object lock = new Object();
private final Supplier<T> initializer;
private volatile T value;
public LazyLoader(Supplier<T> initializer) {
this.initializer = initializer;
}
/**
* 直接创建value
*/
public T createValue() {
return initializer.get();
}
/**
* 获取value,如果null则创建
*/
public T getValue() {
if (value == null) {
synchronized (lock) {
if (value == null) {
value = initializer.get();
}
}
}
return value;
}
public boolean isCreated() {
return value != null;
}
}
4.ServiceLoader<T>
package cn.mashang.export_table_java;
import java.util.ArrayList;
import java.util.List;
/**
* 作用描述: 服务加载程序
* 组件描述: #基础组件 #组件名 (子组件)
* 组件版本: v1
* 创建人 rentl
* 创建日期 2022/2/8 20:12
* 修改日期 2022/2/8 20:12
*/
public final class ServiceLoader<T> {
private final Class<T> serviceBaseClass;
private final String serviceName;
public static <T> ServiceLoader<T> build(Class<T> baseClass) {
if (baseClass == null) {
throw new RuntimeException("ServiceLoader baseClass class can't be null");
}
return new ServiceLoader<>(baseClass);
}
private ServiceLoader(Class<T> serviceBaseClass) {
this.serviceBaseClass = serviceBaseClass;
this.serviceName = serviceBaseClass.getName();
}
/**
* 获取所有服务
*/
public List<T> getAllService() {
List<Object> objects = ExportTable.serviceListMap.get(serviceBaseClass);
List<T> tList = new ArrayList<>();
if (objects != null && !objects.isEmpty()) {
for (Object object : objects) {
if (object instanceof LazyLoader) {
Object value = ((LazyLoader) object).getValue();
try {
tList.add((T) value);
} catch (ClassCastException e) {
e.printStackTrace();
}
continue;
}
try {
tList.add((T) object);
} catch (ClassCastException e) {
e.printStackTrace();
}
}
}
return tList;
}
/**
* 获取单实例
*
* @return <T>
*/
public T getSingletonService(final String servicePath) {
if (servicePath == null || servicePath.isEmpty()) {
throw new IllegalArgumentException("getSingleInstance args: path is null");
}
try {
Object o = ExportTable.singletonServiceMap.get(servicePath);
if (o instanceof LazyLoader) {
return (T) ((LazyLoader<?>) o).createValue();
}
return (T) o;
} catch (ClassCastException e) {
e.printStackTrace();
}
return null;
}
/**
* 新实例
*
* @param servicePath
*/
public T newInstance(final String servicePath) {
if (servicePath == null || servicePath.isEmpty()) {
throw new IllegalArgumentException("newInstance args: path is null");
}
final Object o = ExportTable.newServiceMap.get(servicePath);
if (o instanceof LazyLoader) {
try {
return (T) ((LazyLoader<?>) o).createValue();
} catch (ClassCastException e) {
e.printStackTrace();
}
}
try {
return (T) o.getClass().getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
三、应用
lib_arouter
/**
* 作用描述: ARouter应用程序生命周期
* 组件描述:
* 创建人 rentl
* 创建日期 2022/2/9
* 修改日期 2022/2/9
*/
public class ARouterApplicationLifeCycle extends BaseApplicationLifeCycle {
public ARouterApplicationLifeCycle(int initOrder) {
super(initOrder);
}
@Override
public void onCreate() {
if (ProcessHelper.isMainProcess()) { //根据需要
ARouterApp.initARouter(BaseAndroid.StaticCall.sApplication);
}
}
}
public class LibOkHttpExportTable implements ExportTableLoader {
@Override
public void export(ExportTable.Exporter exporter) {
exporter.setSingleton(TableConstants.Path.OkhttpApplicationLifeCycle, ApplicationLifeCycle.class, new OkhttpApplicationLifeCycle(999));
}
}
public class LibARouterExportTable implements ExportTableLoader {
@Override
public void export(ExportTable.Exporter exporter) {
exporter.setSingleton(TableConstants.Path.ARouterApplicationLifeCycle, ApplicationLifeCycle.class, new ARouterApplicationLifeCycle(1000));
}
}
lib_okhttp
public class OkhttpApplicationLifeCycle extends BaseApplicationLifeCycle {
}
lib_baseAndroid
public class BaseAndroidApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
uper.attachBaseContext(base);
MultiDex.install(this);
BaseAndroid.installRun(this);
List<ApplicationLifeCycle> allService = ServiceLoader.build(ApplicationLifeCycle.class).getAllService();
Collections.sort(allService, (o1, o2) -> Integer.compare(o2.getInitOrder(), o1.getInitOrder()));
mApplicationLifeCycles = allService;
for (ApplicationLifeCycle applicationLifeCycle : mApplicationLifeCycles) {
applicationLifeCycle.onBaseContextAttached(base);
}
}
}
app
public final class AppExtTable implements ExportTableLoader {
public static void init() {
ExportTable.initTables(new ExportTableLoader[]{
new AppExtTable(),
new LibOkHttpExportTable(),
new LibARouterExportTable(),
//动态集成模块table可以用反射
});
}
@Override
public void export(ExportTable.Exporter exporter) {
ExportTable.getExporter().setSingleton(TableConstants.ConstantsPath.APP_BUILD_COMPUTER_TIME, long.class, BuildEvn.BUILD_COMPUTER_TIME);
}
}
注册ExportTableLoader
相关类可以通过gradle 分配一个文件夹
baseAndroid.gradle
android {
sourceSets {
main {
if (export_table) {
def export_table_src_dir = 'src/export_table' //java代码文件夹
if (hasAppPlugin) {
//默认包目录
def javaFiles = new File(projectDir, "$export_table_src_dir/cn/mashang/export_table")
if (!javaFiles.exists()) {
javaFiles.mkdirs()
}
}
java.srcDir(project.file(export_table_src_dir))
}
}
}
}
四、总结
例如:以上就是简单实用的android spi机制。