美文网首页
SPI在android中的使用思想

SPI在android中的使用思想

作者: ModestStorm | 来源:发表于2020-06-10 21:06 被阅读0次
SPI(Service Provider Interface)

本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。这样可以在运行时,动态为接口替换实现类。用在模块间降低耦合,同时可以在所有子library中使用。

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("测试");
        }
在android中使用SPI分为以下几个步骤:
1.自定义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)
            }
        }
    }
2.自定义generateTask:使用javassit扫描工程中含有@ServiceProvider注解的*.class字节码文件并收集接口实现类信息写入指定目录下,然后根据指定目录下的文件使用javapoet生成服务注册类ServiceRegistry,建立接口类和实现类的映射关系。
3.调用compileGeneratedTask编译javapoet生成的注册类ServiceRegistry,接下来就可以在代码中使用了。

相关文章

  • SPI在android中的使用思想

    SPI(Service Provider Interface) 本质是将接口实现类的全限定名配置在文件中,并由服务...

  • Android中SPI的使用

    转载注明出处:http://www.jianshu.com/p/a9a8ddcd265b 1. 简介 SPI全称是...

  • Motan SPI 机制

    Motan的两个注解 Spi,在Motan中如果要使用SPI机制,则暴露出来的接口要使用@Spi注解标注,并且可以...

  • 在Android上使用SPI机制

    一. SPI即Service Provider Interfaces.有时候一个接口可能有多种实现方式, 如果将特...

  • dubbo中SPI思想

    1. dubbo基于SPI思想实现 * SPI:   我们系统里抽象的各个模块,往往有很多不同的实现方案,比如日志...

  • 45 SPI(面向接口编程)-简介

    Android端简单易用的SPI框架 —— SPA SPI(Service Provider Interface)...

  • spi工厂-使用

    使用spi spi工厂

  • AspectJ 在 Android 中的使用

    AspectJ 在 Android 中的使用 在介绍 AspectJ 之前,我们先看看常见的几种编程架构思想。 面...

  • Dubbo SPI

    Java提供了SPI机制(ServiceLoader)来进行服务发现,而Dubbo中的扩展点同样使用了SPI机制进...

  • Dubbo SPI的认识

    Dubbo是基于Java原生SPI机制思想的一个改进. 关于JAVA 的SPI机制 SPI全称(service p...

网友评论

      本文标题:SPI在android中的使用思想

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