依赖注入在后端领域开发是一项非常流行的设计模式,在 Google 接手了 Dagger 项目的开发工作之后,随之而来也给移动端带来了新的生机。
何为 Dagger?
它是一个适用于Java 和 Android 开发的编译注解 依赖注入(Dependency Injection, DI)
框架,最早是由Square公司 —— 美国一家移动支付公司开源的(我们的Android之神就入职这家),后来经由Google维护,继而开发出 Dagger2 ,其是在 Dagger1 基础之上开发的一个“船新”版本,但是仍然与Dagger1有比较多的相似之处。只是在相关 API 上,Dagger2 尝试做了更多的修改。当然要认识这一设计模式,首先我们先来了解什么是 依赖注入。
依赖注入
什么是依赖注入?
就是目标类中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建。
大概十五年前,英国著名软件工程师 Marting Fowler 就针对轻量级容器【当时的技术圈顶级流量话题】发表了一篇文章《Inversion of Control Containers and the Dependency Injection pattern》,如果想看中文版翻译,请看这里。这种控制反转的设计模式,后来被唤作 —— 依赖注入。它是由一个装配器来创建对象,并将对象的实例传递给需要依赖的对象,其目的就在于降低对象之期间的耦合性。
在java中,有这几种常见的场景,可以关联对象1和对象2的依赖关系:
对象1作为对象2的构造函数或者方法中的参数;
对象1是对象2的成员变量,或者对象1是对象2方法中的局部变量;
对象1的静态方法被对象2调用。
我们知道,代码耦合性是衡量类与类或模块与模块之间依赖程度的表现之一,SOLID原则:单一职责、开放关闭、里式替换、接口隔离、依赖倒置,这几大原则无一例外均在提现解耦的思想。因此,利用依赖注入的方式,开发者可以不用考虑对象创建,而是依赖装配器将对象的依赖注入进去。
基于此,我们可以将Dagger理解为这样一个框架:利用编译时注解解析,创建对象与对象之间的依赖关系的容器,以及被依赖对象的实例,并将依赖关系注入所需的对象中。
编译时注解解析
传统的依赖注入框架利用Java反射机制实现依赖注入,这样不好的后果就是加载耗时,也耗损性能。Dagger2 是基于编译时注解来解析,通过在编译期间进行依赖注入,在性能上绝对能胜之。APT —— 注解处理器,它是javac的一个工具,用于编译时处理注解,从而生成Java文件。而Dagger2正式利用这一技术实现了在编译期间解析注解,生成相应的装配器等,完成依赖注入。
Dagger2实现原理
Inject注解
Inject 注解是javax包提供的一个用于依赖注入的注解,是Java依赖注入规范(JSR330)提供的标准注解之一。源码如下:
({ METHOD, CONSTRUCTOR, FIELD }) |
有关注解的相关知识可以参考这篇文章,由上可以看出,Inject注解可用于标注方法、构造方法、字段,当Inject注解标注构造方法时,表示Dagger2创建对象实例时,将调用Inject注解标注的构造方法。可以这样理解:
如果一个类没有标注Inject注解,它将无法通过Dagger2实例化,而当 Inject 注解标注构造方法时,也将指示Dagger2构造方法中声明的参数需要被注入依赖关系。
这里要注意,当一个类有多个构造方法,那么就不能通过Inject同时标注多个构造方法,否则会报错,这时如若需要,可以通过 限定符Qualifier 注解协助完成。