Dagger简单使用及实现原理

514 阅读3分钟

这是我参与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/