Dagger多模块项目增量构建性能:独立@Component与Subcomponent选型疑问
Dagger多模块增量构建性能问题解答
问题1:独立@Component通过依赖接口关联的方案是否合理
该方案完全合理,是工业界多模块项目优化Dagger构建性能的公认最佳实践。
你给出的示例实现遵循依赖倒置原则,各模块的组件只依赖抽象的依赖提供者接口,不直接耦合其他模块的具体组件实现,从架构层面就避免了跨模块的Dagger生成代码绑定,完全符合降低增量构建影响范围的优化目标。
interface DependencyProvider { fun provideDep(): SomeDependency } // 第一个Gradle模块 @Component interface FeatureComponent : DependencyProvider {} // 第二个Gradle模块 @Component(dependencies = [DependencyProvider::class]) interface ConsumerComponent { }
问题2:子组件变更是否会触发父组件重新生成
会。
Subcomponent的实现类会作为父Component的内部类生成,二者的生成代码强绑定。只要子组件的依赖图、绑定逻辑发生任何变更,都会触发父Component的生成代码重新编译。如果父Component位于基础公共模块,还会牵连所有依赖该公共模块的其他业务模块重新执行注解处理,大幅降低增量构建缓存命中率。
问题3:独立@Component内部变更未改公共接口是否牵连其他组件
不会。
只要作为跨模块依赖契约的公共接口(如示例中的DependencyProvider)没有发生任何修改,即使功能模块内部的@Component绑定逻辑、依赖图发生变更,Dagger也只会重新生成该功能模块内的相关代码。其他依赖该公共接口的组件所在模块不会触发注解处理和编译流程,可以100%复用之前的构建缓存,这也是独立组件方案对比Subcomponent的核心优势。
Dagger增量注解处理器工作原理
Dagger增量注解处理器基于Gradle的增量注解处理框架实现,核心逻辑是将输入元素和生成代码的映射关系做缓存,构建时仅处理发生变更的输入对应的生成逻辑,分为三类处理级别:
- 隔离型(ISOLATING):占Dagger处理器的绝大多数,比如
@Module、@Provides、@Component的基础处理逻辑,每个注解的生成结果仅和被注解的元素本身有关,单个元素变更只会触发对应少量代码重新生成。 - 聚合型(AGGREGATING):仅用于需要收集多个输入元素的场景,比如全局绑定校验、子组件收集逻辑,只要集合内任意一个输入变更,该聚合逻辑对应的输出会重新生成,多模块拆分后该逻辑仅在单个模块范围内生效,影响范围可控。
- 动态型(DYNAMIC):Dagger原生逻辑没有这一级别,只有当项目引入了不符合增量规范的第三方Dagger扩展时才会降级到该级别,任意变更都会触发全量注解处理。
此外Dagger会单独缓存每个模块对外暴露的绑定契约信息,只要契约没有变更,其他模块不需要重新校验自身依赖图,直接复用缓存即可。
内容的提问来源于stack exchange,提问作者Sviat Volkov
相关产品推荐
相关产品推荐

