and: dagger 抄袭1

ref

Dagger 2 完全解析(一),Dagger 2 的基本使用与原理

https://www.jianshu.com/p/26d9f99ea3bb

notes

什么是依赖注入

依赖注入(Dependency Injection,简称 DI)是用于实现控制反转(Inversion of Control,缩写为 IoC)最常见的方式之一,控制反转是面向对象编程中的一种设计原则,用以降低计算机代码之间耦合度。控制反转的基本思想是:借助“第三方”实现具有依赖关系的对象之间的解耦。一开始是对象 A 对 对象 B 有个依赖,对象 A 主动地创建 对象 B,对象 A 有主动控制权,实现了 Ioc 后,对象 A 依赖于 Ioc 容器,对象 A 被动地接受容器提供的对象 B 实例,由主动变为被动,因此称为控制反转。注意,控制反转不等同于依赖注入,控制反转还有一种实现方式叫“依赖查找”(Denpendency Lookup)。更多控制反转的信息请看控制反转的维基百科。

在这里插入图片描述

依赖注入就是将对象实例传入到一个对象中去(Denpendency injection means giving an object its instance variables)。依赖注入是一种设计模式,降低了依赖和被依赖对象之间的耦合,方便扩展和单元测试。

依赖注入的实现方式

你已经不知觉地使用了依赖注入

基于构造函数,在构造对象时注入所依赖的对象。

public class Man {
    Car car;
    public Man(Car car) {
        this.car = car;
    }
    ...
}

基于 set 方法,使用 setter 方法来让外部容器调用传入所依赖的对象。

public class Man {
    ...
    public void setCar(Car car) {
        this.car = car;
    }
}

基于接口,使用接口来提供 setter 方法。

public interface CarInjector {
    void injectCar(Car car);
}

public class Man implements CarInjector {
    ...
    @Override
    public void injectCar(Car car) {
        this.car = car;
    }
}

基于注解,Dagger 2 依赖注入框架就是使用 @Inject 完成注入。

public class Man {
    @Inject
    Car car;
    ...
}

下面是 Dagger 2 的一些资源地址:

Github:https://github.com/google/dagger

官方文档:https://google.github.io/dagger//

API:http://google.github.io/dagger/api/latest/


public final class Man_MembersInjector implements MembersInjector<Man> {
  private final Provider<Car> carProvider;

  public Man_MembersInjector(Provider<Car> carProvider) {
    assert carProvider != null;
    this.carProvider = carProvider;
  }

  public static MembersInjector<Man> create(Provider<Car> carProvider) {
    return new Man_MembersInjector(carProvider);
  }

  @Override
  public void injectMembers(Man instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.car = carProvider.get();
  }

  public static void injectCar(Man instance, Provider<Car> carProvider) {
    instance.car = carProvider.get();
  }
}

从上面的injectMembers方法中可以看到注入依赖的代码是instance.car = carProvider.get();,所以@Inject标注的成员属性不能是private的,不然无法注入。

上面完成两步,通过 Dagger 2 生成的代码代码可以知道,生成了 Man 的成员属性注入类和 Car 的工厂类,接下来需要的就是新建工厂实例并调用成员属性注入类完成 car 的实例注入。完成这个过程的桥梁就是dagger.Component。

Component 桥梁

@Component可以标注接口或抽象类,Component 桥梁可以完成依赖注入过程,其中最重要的是定义注入接口,调用注入接口就可以完成 Man 所需依赖的注入。
在这里插入图片描述

@Component
public interface ManComponent {

    void injectMan(Man man);  // 注入 man 所需要的依赖

}

build 后会生成带有Dagger前缀的实现该接口的类: DaggerManComponent

public final class DaggerManComponent implements ManComponent {
  private MembersInjector<Man> ManMembersInjector;

  private DaggerManComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  public static ManComponent create() {
    return new Builder().build();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.ManMembersInjector = Man_MembersInjector.create(Car_Factory.create());    // 找到 Man 的成员属性注入类,创建依赖的工厂
  }

  @Override
  public void injectMan(Man man) {
    ManMembersInjector.injectMembers(man);  // 完成依赖注入
  }

  public static final class Builder {
    private Builder() {}

    public ManComponent build() {
      return new DaggerManComponent(this);
    }
  }
}

todo 学习复习建造者 模式

从上面生成的代码可以看出来 Component 就是连接依赖的对象实例和需要注入的实例属性之间的 桥梁Component 会查找目标类对应的成员属性注入类(即 MembersInjector),然后把依赖属性的工厂实例(即 Car_Factory.create())传给注入类,再使用 Component 一开始定义的接口就能完成依赖注入。

注意,Component 中注入接口的参数必须为 需要注入依赖的类型 ,不能是 Man 的父类或子类, 必须就是他这个类本身,注入接口返回值为 void,接口名可以任意。

接下来只需要在 Man 中调用injectMan方法就能完成注入。

public class Man {
    ...
    public Man() {
        DaggerManComponent.create().injectMan(this);
    }
    ...
}

Module

使用@Inject标注构造函数来提供依赖的对象实例的方法,不是万能的,在以下几种场景中无法使用:

接口没有构造函数

第三方库的类不能被标注

构造函数中的参数必须配置

这时,就可以用 @Provides 标注的方法来提供依赖实例,方法的返回值就是依赖的对象实例, @Provides 方法必须在 Module 中, Module 即用 @Module 标注的类。所以 Module 是提供依赖的对象实例的另一种方式。

@Module
public class CarModule {
    @Provides
    static Car provideCar() {
        return new Car();
    }
}

约定俗成的是@Provides方法一般以provide为前缀,Moudle 类以Module为后缀,一个 Module 类中可以有多个@Provides方法。

接下来,需要把可以提供依赖实例的 Module 告诉 Component:

@Component(modules = CarModule.class)
public interface ManComponent {

    void injectMan(Man man);  // 注入 man 所需要的依赖

}

build之后,Module 和 Component 生成的类为:

public final class CarModule_ProvideCarFactory implements Factory<Car> {
  private static final CarModule_ProvideCarFactory INSTANCE = new CarModule_ProvideCarFactory();

  @Override
  public Car get() {
    return Preconditions.checkNotNull(
        CarModule.provideCar(), "Cannot return null from a non-@Nullable @Provides method");
  }

  public static Factory<Car> create() {
    return INSTANCE;
  }

  /** Proxies {@link CarModule#provideCar()}. */
  public static Car proxyProvideCar() {
    return CarModule.provideCar();
  }
}

CarModule_ProvideCarFactory 和之前的 Car_Factory 类似,都实现 Factory 接口。

而生成的 DaggerManComponent 和之前相比只改变了一个方法:

private void initialize(final Builder builder) {
    this.manMembersInjector = Man_MembersInjector.create(CarModule_ProvideCarFactory.create());
}

aka: 只是提供依赖实例的工厂变为了 CarModule 对应的工厂。

总结

现在再来看 Dagger 2 最核心的三个部分:

在这里插入图片描述
下面再讲述上面提到的在 Dagger 2 种几个注解的用法:

@Inject 一般情况下是标注成员属性和构造函数,标注的成员属性不能是private,Dagger 2 还支持方法注入,@Inject还可以标注方法。
@Provides 只能标注方法,必须在 Module 中。
@Module 用来标注 Module 类
@Component 只能标注接口或抽象类,声明的注入接口的参数类型必须和目标类一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值