Dagger2依赖注入之依赖哪里来

226 阅读2分钟

一.dagger2是一个依赖于编译器实现自动依赖注入的库

那么它是怎么实现依赖注入的?依赖从哪里来?又要注入到哪里去?这篇文章先来讲讲依赖从哪里来

二.中介者Component组件

获取依赖和注入依赖都依赖于Component组件,Component组件类就像一个中介者,链接依赖类和注入类。 怎么定义一个Component?很简单,接口+@Component注解

@Component
interface ProvideComponent {}

dagger2是一个依赖于编译器实现自动依赖注入的,因此学习Dagger2一定要看看编译器生成的类是咋样的。

编译器根据@Component注解的接口自动生成中介者Component组件类
从上图看,这个中介者既没有获取依赖也没有注入依赖的能力,要想知道依赖从哪里来,还需要以下的一些操作。

三.依赖从哪里来?

  • 通过@Inject注解:在依赖类的构造函数添加@Inject,并在@Component注解的组件接口中定义获取依赖的方法,然后再编译一下看看自动生成组件类
class Pig @Inject constructor():Animal{
  override fun description(){
       println("我是小猪佩奇,通过@Inject提供")
   }
}

可以看到组件类可以通过@Inject注解的构造函数提供依赖类了

  • 通过@Module注解:想要获取接口或第三方库中类的依赖时,没办法通过@Inject的方式,那么此时可以用@Module的方式提供;而且如果同时用两种方式提供依赖,那么中介者最终只会采用@Module注解方式

使用方式:

  1. 在提供依赖的类上添加 @Module 注解
  2. 在提供依赖的类的方法上添加 @Provides/@Binds 注解
  3. 在Comment 上@Component注解上添加相应的参数(如ProvideComponent的(modules = [ParamModule::class]))
@Module
class ParamModule constructor(val name:String) {
   @Provides
   fun provideFish():Fish{
       return Fish(name)
   }
}
@Component(modules = [ParamModule::class])
interface ProvideComponent {
  fun getPig(): Pig
  fun getFish():Fish    
}

可以看到Fish最终是由ParamModule类提供的

fun main() {
     //静态方法create()快速创建Dagger组件
  //DaggerProvideComponent.create().run {
  //     getPig().description()
  // }

  //建造者模式创建Dagger组件,当组件需要传值时(如添加了有参构造函数的ParamModule时)一定得>使用建造者模式创建
  //并且需要手动设置module,不然会报错
  DaggerProvideComponent.builder().paramModule(ParamModule("鲤鱼泡泡")).build().run {
      getPig().description()
       getFish().description()
  }
}
  • 通过自定义中介者Builder和@BindsInstance注解。module类的构造函数参数最多只能有一个形参,而这种方式能代替module构造函数传参,且没有个数限制。这种方式和@Module注解方式不能同时提供依赖类(使用了限定符注解的情况除外),且优先级也是比@Inject注解方式高的
@Component
interface BindsInstanceComponent {
   fun getName():String

   @Component.Builder
   interface Builder{

       @BindsInstance
      fun userName(name:String):Builder
       //返回中介者的方法必须要定义
      fun build():BindsInstanceComponent
   }
}
fun main(args: Array<String>) {
  DaggerBindsInstanceComponent.builder().userName("gyq").build().run{
     println("name: ${getName()}")
  }
}

4.demo地址