Android-模块化通信-简单实用的android spi机制


前言

为了实现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机制。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值