这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战
什么是依赖注入
依赖注入是一种面向对象的编程模式,它的出现是为了降低耦合性,所谓耦合就是类之间的依赖关系,所谓降低耦合就是降低类和类之间的依赖关系.
在我们日常编程中,时常都在使用依赖注入.比如:当我们在一个类的构造函数中通过参数引入另一个类对象时,或者是通过set方法设置一个类的对象其实就是使用了依赖注入.
依赖注入通常有一下几种方式:
- 通过接口注入
fun main() {
val aaa: ClassAAA = ClassAAA()
ClassBBB().setClassAAA(aaa)
}
interface TestInteface{
fun setClassAAA(aaa: ClassAAA)
}
/**
* 依赖ClassAAA的类
*/
class ClassBBB :TestInteface {
var aaa : ClassAAA? = null
override fun setClassAAA(aaa: ClassAAA) {
this.aaa = aaa
}
}
/**
* 要被依赖注入的类
*/
class ClassAAA {
}
- 使用set方法注入[也是最常用的一种方式]
class ClassAAA {
}
class ClassBBB {
var classA: ClassAAA? = null
fun setClassAAA(classA: ClassAAA?) {
this.classA = classA
}
}
- 通过构造方法注入
class ClassA(b: ClassAAA) {
var classB: ClassAAA
init {
classB = b
}
}
- 过注解的方式注入[inject方式]
class ClassAAA {
}
class ClassBBB {
@Inject
val classAAA: ClassAAA? = null
}
使用类实例化实现以下例子, 我们创建一个名为TestDagger.kt
的类:
fun main() {
TestDagger().testFunction()
}
class TestEntity constructor(val value :String = "不怎么样")
class TestDagger {
fun testFunction() {
val test = TestEntity()
println("今天天气 ${test.value}")
}
}
使用dagger实现上述逻辑
@Component
interface TestComponent {
fun inject(test: TestDagger?)
}
class TestDagger {
constructor() {
DaggerTestComponent.builder().build().inject(this)
}
@Inject
lateinit var test: TestEntity
fun testFunction() {
println("今天天气 ${test.value} ${test.test1}")
}
}
class TestEntity @Inject constructor() {
val value = "不怎么样"
val test1 = "另外一个属性"
}
可以看到, dagger在这个时候没有任何优势,需要写很多代码才能实现
Dagger初衷也不是这个,而是为了解决庞大项目我们剖析一下dagger自动生成的代码
生成了三个类, 分别是:DaggerTestComponent.java
, TestDagger_MembersInjector.java
以及 TestEntity_Factory.java
我们分别看一下这三个类
首先看DaggerTestComponent.java
public final class DaggerTestComponent implements TestComponent {
private DaggerTestComponent() {
}
public static Builder builder() {
return new Builder();
}
public static TestComponent create() {
return new Builder().build();
}
@Override
public void inject(TestDagger test) {
injectTestDagger(test);}
private TestDagger injectTestDagger(TestDagger instance) {
TestDagger_MembersInjector.injectTest(instance, new TestEntity()); //第一处
return instance;
}
public static final class Builder {
private Builder() {
}
public TestComponent build() { //第二处
return new DaggerTestComponent();
}
}
}
主要重点有两处
- 第一处: 我们通过
injectTest(... , ...)
将TestEntity
类注入到TestDagger_MembersInjector
成员类中 - 第二处 通过build构建个dagger为我们生成的
DaggerTestComponent
类 这两处结合为一处代码便是我们自己代码TestDagger.kt
中的DaggerTestComponent.builder().build().inject(this)
我们再详细看看,为什么我们没有实例化TestEntity
,而只是加了一个@Inject就可以让我们拿到实体对应的数据呢?
其实原因还得从源码中找
我们还是看DaggerTestComponent.java
第一处
TestDagger_MembersInjector.injectTest(instance, new TestEntity()); //第一处
如上代码可以看出,dagger帮我们实现了new TestEntity()
进入injectTest
方法我们可以看到
public final class TestDagger_MembersInjector implements MembersInjector<TestDagger> {
...
@InjectedFieldSignature("com.eegets.frame.dagger.TestDagger.test")
public static void injectTest(TestDagger instance, TestEntity test) {
instance.test = test;
}
}
可以看到,Dagger自动将我们刚才实例化的TestEntity设置给了TestDagger的test对象,这个test对象就是我们自己写的TestDagger.kt中标记了@Inject的test
变量
这样我们就全部明白了,其实并不是我们没有实例化,而是dagger在自己生成的代码中进行了实例化并且进行了赋值.
本篇文章从Dagger源码层面了解了Dagger实现依赖注入的原理以及如何实现一个简单的Dagger实例
为什么要写这一篇简单的文章,主要是为了对下一篇文章Hilt实现依赖注入
的接入和理解使用提供铺垫.
更多Dagger的使用请查看官网 dagger.dev/