组件化架构之组件初始化 Component Initializer(组件初始化器)开源项目 原理分析

本文介绍了Component Initializer组件初始化器的开源项目,详细阐述了其如何通过Transform API实现组件自动注册,以及配置组件初始化依赖的处理方式。文章通过分析项目原理,包括自动注册的挑战、解决方案以及依赖关系图的生成,为读者揭示了组件化架构中的一个重要环节。
摘要由CSDN通过智能技术生成

Component Initializer(组件初始化器)开源项目 介绍

Component Initializer(组件初始化器)介绍

原理分析

  • 问题1:该框架是如何实现Component类的自动注册的

刚开始我想到的方案是通过注解来实现。首先用@Component注解标记Component类,然后我们用注解处理器就可以拿到Component类的信息,然后利用注解处理器自动生成ComponentInitializer.java类,将收集到的Component类的初始化代码new Component(),添加到ComponentInitializer类中,这样就可以完成自动注册的功能。

看着方案很完美,实际做的时候发现一个问题,就是对于多module的形式,每个module都是独立编译的,都会独立编译成一个aar文件,这也就是为什么我们如果用annotationProcessor的时候需要在每个用到的module上都添加annotationProcessor。这样就会导致我们通过annotationProcessor只能拿到当前module中的Component类的信息。无法拿到用户在各个组件module中配置的所有的Component类的信息。

所以通过annotationProcessor来实现自动注册是行不通的。

那么有没有其他方案呢?

后来我在想,这个问题做框架的是都需要考虑的,那么其他框架是怎么解决的呢。Arouter是如何解决这个问题的?从Arouter的介绍中我发现它是通过AutoRegister来解决的,然后通过AutoRegister的实现原理,我发现它是通过Transform API的技术方案来解决的。

Transform API是从Gradle 1.5.0版本之后提供的,它允许第三方在打包Dex文件之前的编译过程中修改.class字节码文件,这样在这个过程中,我们就可以搜集到所有的Component类,然后通过修改ComponentInitializer.class字节码文件,就可以把注册的代码添加到ComponentInitializer.class字节码文件里。

除了Transform API的方案,其实还有其他两种技术方案。(以下来自AutoRegister作者的分析)

  • ARouter的解决方案。
    AutoRegister在ARouter里是一个可选方案,ARouter本身还有一个解决方案:每个module都生成自己的java类,这些类的包名都是’com.alibaba.android.arouter.routes’,然后在运行时通过读取每个dex文件中的这个包下的所有类通过反射来完成映射表的注册,详见ClassUtils.java源码

  • ActivityRouter的解决方案(demo中有2个组件名为’app’和’sdk’):

    • 在主app module中有一个@Modules({“app”, “sdk”})注解用来标记当前app内有多少组件,根据这个注解生成一个RouterInit类
    • 在RouterInit类的init方法中生成调用同一个包内的RouterMapping_app.map
    • 每个module生成的类(RouterMapping_app.java 和 RouterMapping_sdk.java)都放在com.github.mzule.activityrouter.router包内(在不同的aar中,但包名相同)
    • 在RouterMapping_sdk类的map()方法中根据扫描到的当前module内所有路由注解,生成了调用Routers.map(…)方法来注册路由的代码
    • 在Routers的所有api接口中最终都会触发RouterInit.init()方法,从而实现所有路由的映射表注册

    这种方式用一个RouterInit类组合了所有module中的路由映射表类,运行时效率比扫描所有dex文件的方式要高,但需要额外在主工程代码中维护一个组件名称列表注解: @Modules({“app”, “sdk”})

我们最终选择的是利用AutoRegister的能力来实现自动注册。为了方便用户使用我自定义了一个Gradle plugin来实现此功能

  • 自定义Gradle plugin
class Plugin implements org.gradle.api.Plugin<Project> {
   

    @Override
    void apply(Project project) {
   
        /**
         * 注册transform接口
         */
        def isApp = project.plugins.hasPlugin(AppPlugin)
        if (isApp) {
   
            println 'project(' + project.name + ') apply com.jst.component.initializer plugin'
            def android = project.extensions.getByType(AppExtension)
            def transformImpl = new RegisterTransform(project)

            AutoRegisterConfig config = new AutoRegisterConfig()
            Map<String, Object> map = new HashMap<>()
            map.put('scanInterface','com.jst.compinit.IComponentInfo')
            map.put('codeInsertToClassName','com.jst.compinit.ComponentInitializer')
            map.put('registerMethodName','register')

            config.registerInfo.add(map)
            config.project = project
            config.convertConfig()
            transformImpl.config = config
            android.registerTransform(transformImpl)
        }
    }
}
  • 问题2:该框架是如何实现配置组件的初始化依赖的

首先该依赖信息通过注解的方式来配置是最方便的。所以我们定义了一个@Component注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Component {
   

    /**
     * Component的name
     *
     * 一般情况下该name可以不设置
     * 如果该Component被其他Component所依赖,则该name必须设置
     */
    String name() default "";

    /**
     * 依赖的Component的name列表
     */
    String[] dependencies(
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值