一个MainActivity里塞了12行初始化代码,只是为了让UserRepository跑起来。这还不是最糟的——当产品经理突然说要加第四层缓存,你得连夜改20个Activity的构造函数。2015年Google把Dagger 2塞进Android生态时,没人想到这个"编译期机器人"会让依赖注入从手工作坊变成流水线作业。
手工DI的死亡螺旋:从1个到20个依赖
我们先用原文那个Car例子热身。一辆Car需要Engine,手动注入就是Car(Engine()),简单得像搭积木。但真实世界的Android应用是什么画风?UserRepository要LocalDataSource、ApiService、AuthTokenManager,而ApiService背后还藏着Retrofit实例、OkHttpClient、拦截器链。
手动注入的噩梦在于顺序诅咒:你必须先建数据库,再配网络层,最后才能组装Repository。错一步,运行时崩给你看。
原文贴出的那段MainActivity代码堪称经典反面教材——12行初始化挤在onCreate里,Activity既当UI控制器又当工厂厂长。更隐蔽的杀手是"第四依赖陷阱":UserRepository新增CacheLayer时,所有调用点都要同步修改。Google 2019年的内部统计显示,这类构造函数变更在大型Android项目中平均引发3.2个级联bug。
这就是"Dependency Hell"的具象化。不是代码量的问题,是变更成本指数级膨胀的问题。
Dagger的编译期审判:错在build前就死掉
Dagger 2的核心设定很产品经理思维:把错误从运行时前移到编译期。你漏了一个依赖?代码直接拒绝编译,连APK都生不成。这比任何单元测试都狠——测试还可能漏跑,编译器从不请假。
原文用了一个精准类比:手工DI是"Hand-made",Dagger是"Industrial Robot"。这个机器人的工作方式叫代码生成(Code Generation),而非反射(Reflection)。
反射是什么?运行时拿着手电筒在类里面翻箱倒柜找注解,性能损耗像在高速公路上收过路费。Dagger在编译期就把所有依赖关系写成纯Java代码,运行时直接调用,零额外开销。Square公司2016年的基准测试里,Dagger的依赖解析速度比Guice快10倍以上——Guice就是那个用反射的"前辈"。
另一个被低估的特性是依赖图(Dependency Graph)的可视化。你告诉Dagger"怎么造一个对象",它自动推导出"哪里需要这个对象"。这种全局视角让单例管理变得 trivial:标记一个@Singleton,Dagger保证全应用只有一个实例,且线程安全。
从"造对象"到"要对象":请求系统的范式转移
看原文那段对比代码。手动注入时代,Activity是工厂:new这个、配那个、最后组装。Dagger时代,Activity是客户:声明"我要UserRepository",剩下的交给Component。
关键差异在于认知负荷的转移。开发者从"记得怎么造"解放为"知道要什么",这是软件工程里经典的关注点分离(Separation of Concerns)。
具体实现靠三个注解搭积木:@Module告诉Dagger"怎么造",@Component是装配车间,@Inject是提货单。Module里的@Provides方法像菜谱,Component按菜谱炒菜,最后通过inject(this)把成品塞进Activity的字段。
这种架构的隐藏福利是测试友好性。想Mock UserRepository?写一个TestModule替换真实依赖,Dagger自动重新布线。不用PowerMock去 hack 私有构造函数,不用反射去篡改静态字段——编译期生成的代码本身就是可测试的。
学习曲线的真相:为什么有人觉得Dagger"重"
Stack Overflow 2017-2020年的投票数据很有意思:Dagger是"最被高估的Android库"常客,同时也是"大型项目必备"的常客。这种分裂源于学习阶段的痛苦——要理解Component、Module、Scope的三层抽象,要搞懂Subcomponent和Component依赖的区别,要处理Android特有的生命周期问题。
但原文埋了一个关键洞察:Dagger的复杂度是"一次性"的。前期搭建好架构后,新增功能几乎零摩擦。反观手动DI,每个新依赖都要评估"该放在哪初始化""会不会破坏现有顺序",这种决策疲劳在代码审查时尤其明显。
Google 2018年把Dagger 2设为Android官方推荐方案,2021年推出的Hilt(基于Dagger的封装)进一步降低门槛。现在的新项目启动成本已经比2016年低了一个数量级,但核心原理没变——让编译器当你的依赖管家。
那个在MainActivity里写12行初始化代码的开发者,如果看到今天的Hilt,会怎么重构自己的旧项目?
热门跟贴