SPI机制

作者: ModestStorm | 来源:发表于2022-07-05 14:50 被阅读0次

    SPI:由于业务模块进行了组件拆分,开发了基于SPI组件通信方式,用在模块间降低耦合,解决业务模块的通信问题。可以在业务aar中使用。是Arouter框架服务间调用仅使用于java源文件的功能拓展。

    A模块,B模块都依赖于Common基础服务模块,A模块需要调用B模块提供的数据,B模块也需要调用A模块提供的数据,Common模块与A模块,B模块都依赖于SPI插件。

    实现原理:
    SPI(Service Provider Interface)
    本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载具体实现类。这样可以在运行时,动态为接口替换实现类。用在模块间降低耦合,适合在业务aar中使用,解决了业务模块间的通信问题。

    1.自定义gradle插件:ServiceProviderInterfacePlugin implements Plugin<Project>

    2.自定义generateServiceRegistry task,它的执行时机在javaCompile编译之后,根据传入的编译后的字节码路径,使用javassit扫描工程中含有@ServiceProvider注解的*.class字节码文件并收集接口实现类信息写入指定目录文件,然后根据指定目录下的文件使用javapoet生成服务注册类ServiceRegistry,建立接口类和实现类的映射关系。就可以调用ServiceLoader.load(interface.Class)获取具体接口实现类。

    3.最后调用自定义compileGeneratedTask编译javapoet生成的注册类ServiceRegistry,接下来就可以在代码中使用了。

    // ServiceProvider注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ServiceProvider {
    
        Class<?> [] value();
    
        int priority() default 0;
    
        String alias() default "";
    }
    

    具体接口实现类:

    @ServiceProvider(ITest.class)
    public class Test implements ITest{
       public static String hello="hello";
    
        @Override
        public void printMessage(String msg) {
            Log.e("stormzsl",msg);
        }
    }
    

    调用方式:

     for (ITest test : ServiceLoader.load(ITest.class)) {
                test.printMessage("测试");
            }
    

    自定义gradle插件:

     ServiceProviderInterfacePlugin implements Plugin<Project>{
    
        @Override
        void apply(final Project project) {
            project.dependencies {
                api 'com.fasten.component.spi:loader:1.0.0'
                api 'com.fasten.component.spi:annotations:1.0.0'
            }
    
            project.afterEvaluate {
                try {
                    if (!project.plugins.hasPlugin(Class.forName('com.android.build.gradle.AppPlugin'))) {
                        return
                    }
                } catch (final ClassNotFoundException e) {
                    throw new GradleException("Android gradle plugin is required", e)
                }
    
                project.android.applicationVariants.all { variant ->
                    def spiSourceDir = project.file("${project.buildDir}/intermediates/spi/${variant.dirName}/src")
                    //variant.dirName=debug/release,下面以debug为构建类型的输出
                    println(">>>>>>> variant.dirName=${variant.dirName}")
    
                    // spiSourceDir=/Users/didi/develop/practiceProject/androidSPI/app/build/intermediates/spi/debug/src
                    println(">>>>>>> spiSourceDir=${spiSourceDir}")
    
                    // spiServicesDir=/Users/didi/develop/practiceProject/androidSPI/app/build/intermediates/spi/debug/services
                    def spiServicesDir = project.file("${project.buildDir}/intermediates/spi/${variant.dirName}/services")
                    println(">>>>>>> spiServicesDir=${spiServicesDir}")
    
                    def spiClasspath = project.files(project.android.bootClasspath, variant.javaCompile.classpath, variant.javaCompile.destinationDir)
                    println(">>>>>>> spiClasspath=${spiClasspath}")
    
                    // project.android.bootClasspath=[/Users/didi/Library/Android/sdk/platforms/android-28/android.jar]
                    println(">>>>>>> project.android.bootClasspath=${project.android.bootClasspath}")
    
                    // variant.javaCompile.classpath=file collection
                    println(">>>>>>> variant.javaCompile.classpath=${variant.javaCompile.classpath}")
    
                    //variant.javaCompile.destinationDir=/Users/didi/develop/practiceProject/androidSPI/app/build/intermediates/javac/debug/classes
                    println(">>>>>>> variant.javaCompile.destinationDir=${variant.javaCompile.destinationDir}")
    
                    println(">>>>>> variant.name=${variant.name}  variant.name.capitalize()=${variant.name.capitalize()}")
                    def generateTask = project.task("generateServiceRegistry${variant.name.capitalize()}", type: ServiceRegistryGenerationTask) {
                        description = "Generate ServiceRegistry for ${variant.name.capitalize()}"
                        classpath += spiClasspath
                        sourceDir = spiSourceDir
                        servicesDir = spiServicesDir
                        outputs.upToDateWhen { false }
                    }
    
                    def compileGeneratedTask = project.task("compileGenerated${variant.name.capitalize()}", type: JavaCompile) {
                        description = "Compile ServiceRegistry for ${variant.name.capitalize()}"
                        source = spiSourceDir
                        include '**/*.java'
                        classpath = spiClasspath
                        destinationDir = variant.javaCompile.destinationDir
                        sourceCompatibility = '1.5'
                        targetCompatibility = '1.5'
                    }
    
                    generateTask.mustRunAfter(variant.javaCompile)
                    compileGeneratedTask.mustRunAfter(generateTask)
                    variant.assemble.dependsOn(generateTask, compileGeneratedTask)
                }
            }
        }
    

    相关文章

      网友评论

          本文标题:SPI机制

          本文链接:https://www.haomeiwen.com/subject/vosarrtx.html