Dagger2系列详解(一):@Inject注解

开篇

@Inject的字面含义为“注入”,它的作用有两个:①表达依赖注入诉求②提供依赖


表达依赖诉求

①标记Field

@Inject修饰一个类的Field,即表示向dagger框架表达注入诉求,要求获得一个该Field的实例。dagger框架将负责创建对象并赋予该Field

public class SuperMarket {
    @Inject
    protected Apple apple;

    public SuperMarket() {

    }
}

上面的代码,SuperMarket的成员变量apple@Inject修饰后,dagger框架将负责创建一个Apple实例并赋值给apple。点击android studio的绿色锤子编译一下,看一下这一步dagger为我们做了什么。

你会发现dagger为SuperMarket生成了一个类:SuperMarket_MembersInjector
在这里插入图片描述
源码如下,

public final class SuperMarket_MembersInjector implements MembersInjector<SuperMarket> {
  private final Provider<Apple> appleProvider;

  public SuperMarket_MembersInjector(Provider<Apple> appleProvider) {
    this.appleProvider = appleProvider;
  }

  public static MembersInjector<SuperMarket> create(Provider<Apple> appleProvider) {
    return new SuperMarket_MembersInjector(appleProvider);
  }

  @Override
  public void injectMembers(SuperMarket instance) {
    injectApple(instance, appleProvider.get());
  }

  @InjectedFieldSignature("com.example.daggersample.SuperMarket.apple")
  public static void injectApple(SuperMarket instance, Apple apple) {
    instance.apple = apple;
  }
}

实际上,一个类在表达依赖诉求后,dagger会为其生成一个成员注入器,命名规则依赖诉求方类名_MembersInjector,如SuperMarket_MembersInjector

首先,成员注入器为会为依赖诉求方每一个需要注入的Field生成一个static的注入方法,如SuperMarket_MembersInjectorSuperMarket.apple生成了injectApple方法。该方法接受依赖诉求方(SuperMarket)和待注入的对象(Apple)为参数,进行注入操作,也就是简单的赋值操作。

另外,注入器还会生成一个injectMembers的实例方法,该方法接受依赖诉求方为参数,内部依次调用每个Field的静态注入方法完成注入。其中待注入的对象由每个FieldProvider<T>提供,如Provder<Apple>Provider<T>是一个泛型接口,只有一个get方法,负责提供一个T型实例。创建注入器对象时,会传入每个Field对应的Provider<T>

总结来看,成员注入器本身并不负责生成待注入的对象,只负责简单的注入操作而已。dagger框架既可以直接通过静态注入方法为依赖诉求方注入成员,也可以创建注入器实例并传入对应成员的Provider,然后调用injectMembers方法进行注入。至于何时采用静态方法,何时采用injectMembers下一篇:Dagger2系列详解(二):@Component注解揭晓。

注意,apple的访问限制符不可以为private,否则编译报错,因为dagger框架无法访问到它。
在这里插入图片描述

②标记方法

下面两种情况,@Inject标记Field的方式无法表达依赖注入诉求,

  • 基于不想破坏Field的封装性等原因,需要为Field添加private访问控制符
  • Field由父类(第三方类)继承而来,无法为其添加@Inject注解,甚至子类没有访问Field的权限,只能通过getter/setter方法访问

此时,我们可以先自定义一个方法,方法名任意,形参为Field对应类型,然后用@Inject标记该方法。例如,

public class SuperMarket {
    private Apple apple;

    public SuperMarket() {

    }
    
    /**
     * 该方法为dagger框架调用,并传入待注入的实例,故不可为private修饰,笔者注释
     */
    @Inject
    public void oneAppleInto(Apple apple) {
    	//这里直接访问apple为其赋值
    	//假如apple由于父类继承而来,而子类又没有访问权,可以通过Field的setter为其赋值
        //笔者注释
        this.apple = apple;
    }
}

看一下,dagger生成的SuperMarket_MembersInjector和之前有何不同。

public final class SuperMarket_MembersInjector implements MembersInjector<SuperMarket> {
	
	...

  @Override
  public void injectMembers(SuperMarket instance) {
    injectOneAppleInto(instance, appleProvider.get());
  }

  public static void injectOneAppleInto(SuperMarket instance, Apple apple) {
    instance.oneAppleInto(apple);
  }
}

你会发现,SuperMarket.apple的静态注入方法变成了inject + 依赖诉求方标记的方法名,并且内部通过诉求方标记的方法进行注入操作。

提供依赖

@Inject修饰一个类的构造方法,即告知dagger:当需要为诉求方注入该类的实例时,可以调用该构造方法获取该类的实例然后注入。

public class Apple {
    @Inject
    public Apple() {

    }
}

编译一下,看看会发生什么,
在这里插入图片描述
dagger为Apple生成了一个工厂类Apple_Factory

public final class Apple_Factory implements Factory<Apple> {
  @Override
  public Apple get() {
    return newInstance();
  }

  public static Apple_Factory create() {
    return InstanceHolder.INSTANCE;
  }

  public static Apple newInstance() {
    return new Apple();
  }

  private static final class InstanceHolder {
    private static final Apple_Factory INSTANCE = new Apple_Factory();
  }
}

工厂类的命名规则依赖提供方_Factory,内部类InstanceHolder缓存了工厂类实例,每次调用工厂类的get方法,他都会调用依赖提供方Apple中用@Inject标注的构造方法构建一个新的实例并返还给调用方。

结语

现在我们知道了:

  • @Inject标记一个类的Field或Method意为向dagger表达依赖注入请求。dagger将为其生成一个成员注入器(MembersInjector)负责注入操作,但本身并不负责创建要注入的实例,由注入器的调用方直接提供。

  • @Inject标记一个类的构造方法后,dagger将为其生成一个工厂类,工厂类负责生产该实例以对外提供依赖。

那么,谁负责生产实例(调用工厂方法或构造器),然后再调用成员注入器把这些实例注入依赖诉求方呢?答案是@Component


下一篇:Dagger2系列详解(二):@Component注解

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vincent(朱志强)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值