Dagger2源码分析(三)从源码角度分析注解在Dagger2中的使用

public interface CarComponent {
void inject(Car car);
}

完成这些之后我们需要Build下项目,让Dagger2帮我们生成相关的Java类。接着我们就可以在Car的构造函数中调用Dagger2生成的DaggerCarComponent来实现注入(这其实在前面Car类的代码中已经有了体现)

public class Car {
/**

  • @Inject:@Inject有两个作用,一是用来标记需要依赖的变量,以此告诉Dagger2为它提供依赖
    */
    @Inject
    Engine engine;

public Car() {
DaggerCarComponent.builder().build().inject(this);
}

public Engine getEngine() {
return this.engine;
}

public static void main(String … args){
//TODO:
Car car = new Car();
System.out.println(car.getEngine());
}
}

2、案例B

如果创建Engine的构造函数是带参数的呢?比如说制造一台引擎是需要齿轮(Gear)的。或者Eggine类是我们无法修改的呢?这时候就需要@Module和@Provide上场了。

同样我们需要在Car类的成员变量Engine上加上@Inject表示自己需要Dagger2为自己提供依赖;Engine类的构造函数上的@Inject也需要去掉,应为现在不需要通过构造函数上的@Inject来提供依赖了。

public class Engine {

private String name;

@Inject
Engine(){}

Engine(String name) {
this.name = name;
}

@Override
public String toString() {
return “Engine{” +
“name=’” + name + ‘’’ +
‘}’;
}

public void run() {
System.out.println(“引擎转起来了~~~”);
}
}

接着我们需要一个Module类来生成依赖对象。前面介绍的@Module就是用来标准这个类的,而@Provide则是用来标注具体提供依赖对象的方法(这里有个不成文的规定,被@Provide标注的方法命名我们一般以provide开头,这并不是强制的但有益于提升代码的可

《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》

【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享

读性)。

@Module
public class MarkCarModule {

public MarkCarModule(){ }

/**

  • 用于标注Module所标注的类中的方法,该方法在需要提供依赖时被调用,从而把预先提供好的对象当做依赖给标注了@Inject的变量赋值
  • @return
    */
    @Provides
    Engine provideEngine(){
    return new Engine(“gear”);
    }
    }

接下来我们还需要对CarComponent进行一点点修改,之前的@Component注解是不带参数的,现在我们需要加上modules = {MarkCarModule.class},用来告诉Dagger2提供依赖的是MarkCarModule这个类。

@Component(modules = MarkCarModule.class)
public interface CarComponent {
void inject(Car car);
}

Car类的构造函数我们也需要修改,相比之前多了个markCarModule(new MarkCarModule())方法,这就相当于告诉了注入器DaggerCarComponent把MarkCarModule提供的依赖注入到了Car类中。

public class Car {
/**

  • 我们提到@Inject和@Module都可以提供依赖,那如果我们即在构造函数上通过标记@Inject提供依赖,有通过@Module提供依赖Dagger2会如何选择呢?具体规则如下:
  • 步骤1:首先查找@Module标注的类中是否存在提供依赖的方法。
  • 步骤2:若存在提供依赖的方法,查看该方法是否存在参数。
  • a:若存在参数,则按从步骤1开始依次初始化每个参数;
  • b:若不存在,则直接初始化该类实例,完成一次依赖注入。
  • 步骤3:若不存在提供依赖的方法,则查找@Inject标注的构造函数,看构造函数是否存在参数。
  • a:若存在参数,则从步骤1开始依次初始化每一个参数
  • b:若不存在,则直接初始化该类实例,完成一次依赖注入
    */
    @Inject
    Engine engine;

public Car() {
DaggerCarComponent.builder().markCarModule(new MarkCarModule())
.build().inject(this);
}

public Engine getEngine() {
return this.engine;
}

public static void main(String … args){
//TODO:
Car car = new Car();
System.out.println(car.getEngine());
}
}

这样一个最最基本的依赖注入就完成了,接下来我们测试下我们的代码。
输出

Engine{name=‘gear’}

3、案例C

那么如果一台汽车有两个引擎(也就是说Car类中有两个Engine变量)怎么办呢?没关系,我们还有@Qulifier!首先我们需要使用Qulifier定义两个注解:

public class Engine {

/**

  • 用于自定义注解,也就是说@Qulifier就如同Java提供的几种基本元注解一样用来标记注解类。我们在使用@Module来标注提供依赖的方法时,方法名我们是可以随便定义的(虽然我们定义方法名一般以provide开头,但这并不是强制的,只是为了增加可读性而已)。那么Dagger2怎么知道这个方法是为谁提供依赖呢?答案就是返回值的类型,Dagger2根据返回值的类型来决定为哪个被@Inject标记了的变量赋值。但是问题来了,一旦有多个一样的返回类型Dagger2就懵逼了。@Qulifier的存在正式为了解决这个问题,我们使用@Qulifier来定义自己的注解,然后通过自定义的注解去标注提供依赖的方法和依赖需求方(也就是被@Inject标注的变量),这样Dagger2就知道为谁提供依赖了。----一个更为精简的定义:当类型不足以鉴别一个依赖的时候,我们就可以使用这个注解标示
    1. 使用@Qulifier定义两个注解
      */
      @Qualifier
      @Retention(RetentionPolicy.RUNTIME)
      public @interface QualifierA { }
      @Qualifier
      @Retention(RetentionPolicy.RUNTIME)
      public @interface QualifierB { }

private String name;

Engine(String name) {
this.name = name;
}

@Override
public String toString() {
return “Engine{” +
“name=’” + name + ‘’’ +
‘}’;
}

public void run() {
System.out.println(“引擎转起来了~~~”);
}
}

同时我们需要对依赖提供方做出修改

@Module
public class MarkCarModule {

public MarkCarModule(){ }

/**

    1. 同时我们需要对依赖提供方做出修改
  • @return
    */
    @Engine.QualifierA
    @Provides
    Engine provideEngineA(){
    return new Engine(“gearA”);
    }

@Engine.QualifierB
@Provides
Engine provideEngineB(){
return new Engine(“gearB”);
}
}

接下来依赖需求方Car类同样需要修改

public class Car {
/**

    1. 接下来依赖需求方Car类同样需要修改
      */
      @Engine.QualifierA
      @Inject
      Engine engineA;

@Engine.QualifierB
@Inject
Engine engineB;

public Car() {
DaggerCarComponent.builder().markCarModule(new MarkCarModule())
.build().inject(this);
}

public Engine getEngineA() {
return this.engineA;
}

public Engine getEngineB() {
return this.engineB;
}

public static void main(String… args) {
//TODO:
Car car = new Car();
System.out.println(car.getEngineA());
System.out.println(car.getEngineB());
}
}

执行结果:

Engine{name=‘gearA’}
Engine{name=‘gearB’}

4、案例D

接下来我们看看@Scope是如何限定作用域,实现局部单例的。
首先我们需要通过@Scope定义一个CarScope注解:

public class Engine {

/**

  • 用于自定义注解,我能可以通过@Scope自定义的注解来限定注解作用域,实现局部的单例
    1. @Scope定义一个CarScope注解
      */
      @Scope
      @Retention(RetentionPolicy.RUNTIME)
      public @interface CarScope {
      }

private String name;

Engine(String name) {
this.name = name;
System.out.println("Engine create: " + name);
}

@Override
public String toString() {
return “Engine{” +
“name=’” + name + ‘’’ +
‘}’;
}

public void run() {
System.out.println(“引擎转起来了~~~”);
}
}

接着我们需要用这个@CarScope去标记依赖提供方MarkCarModule。

@Module
public class MarkCarModule {

public MarkCarModule(){ }

/**

    1. @CarScope去标记依赖提供方MarkCarModule
  • @return
    */
    @Engine.CarScope
    @Provides
    Engine provideEngine(){
    return new Engine(“gear”);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值