走马观花-Dagger2 - @Inject 和 @Component

@Inject

  • @Inject 使用在一个类的属性上,表示该类需要一个依赖
  • @Inject 使用在一个类的构造方法上,表示由该构造方法提供依赖

假设有个路人Passerby,需要一辆车Car,则可以表示为 Passerby 依赖于 Car。代码表示:

Passerby :

public class Passerby {
    public Car mCar;
    public Passerby(Car car) {
        mCar = car;
        System.out.println("I'm a Passerby!");
    }
}

Car :

public class Car {
    @Inject
    public Car() {
        System.out.println("I'm a Car!");
    }
}

当且仅当在 Car 的构造器上使用 @Inject 时,编译,在 \build\generated\source\apt\debug\com\oliver\test 目录下自动生成了 Car_Factory.java 文件:

public final class Car_Factory implements Factory {
  private static final Car_Factory INSTANCE = new Car_Factory();

  @Override
  public Car get() {
    return provideInstance();
  }

  public static Car provideInstance() {
    return new Car();
  }

  public static Car_Factory create() {
    return INSTANCE;
  }

  public static Car newCar() {
    return new Car();
  }
}

Car_Factory 实现了 Factory 接口, Factory 继承至 Provider 接口:

public interface Factory extends Provider {
}

public interface Provider {
    /**
     *  返回注入的实例
     */
    T get();
}

观察 Car_Factory.java ,可以知道:

  • 构造器使用了 @Inject 注解,就会生成 类名_FactoryFactory 实现类。
  • get() 确实返回我们注入的实例
  • 自动生成两个返回 new Car() 的方法,分别是 newCar()provideInstance()

Passerby 的依赖标注 @Inject 注解,再次编译:

 @Inject
 public Car mCar;

\build\generated\source\apt\debug\com\oliver\test 目录下多了一个 Passerby_MembersInjector 的类:

public final class Passerby_MembersInjector implements MembersInjector {
  private final Provider mCarProvider;

  public Passerby_MembersInjector(Provider mCarProvider) {
    this.mCarProvider = mCarProvider;
  }

  public static MembersInjector create(Provider mCarProvider) {
    return new Passerby_MembersInjector(mCarProvider);
  }

  @Override
  public void injectMembers(Passerby instance) {
    injectMCar(instance, mCarProvider.get());
  }

  public static void injectMCar(Passerby instance, Car mCar) {
    instance.mCar = mCar;
  }
}

该类实现了 MembersInjector 接口:

public interface MembersInjector {
  void injectMembers(T instance);
}

注意 Passerby_MembersInjector 的方法 injectMembers(T instance),其参数是 Passerby 类型,也就是说,该方法的使命就是给其参数持有的成员变量赋值,然后外界想办法获得这个参数就行了,参数依赖的对象已经在此处完成了注入的过程。

 @Override
  public void injectMembers(Passerby instance) {
    injectMCar(instance, mCarProvider.get());
  }

  public static void injectMCar(Passerby instance, Car mCar) {
    instance.mCar = mCar;
  }

另外, Passerby_MembersInjector 多出了一个成员 Provider,即一个类的成员变量标注有 @Inject 注解,那么这个成员就会在生成类中生成相应的 Provider 成员。根据上面对 Car_Factory 的分析,大胆猜测,其实这里的 Provider 就是生成的 Car_Factory 。所需依赖也正好在此处注入,即:

instance.mCar =  mCarProvider.get();
mCar = new Car();


///////////////////////////// Car_Factory /////////////////////////////
@Override
public Car get() {
    return provideInstance();
}

public static Car provideInstance() {
    return new Car();
}

上面说到,我们猜测 Provider 就是生成的 Car_Factory 。那 Provider 是怎样赋值的呢?

public Passerby_MembersInjector(Provider mCarProvider) {
    this.mCarProvider = mCarProvider;
  }

  public static MembersInjector create(
      Provider mCarProvider) {
    return new Passerby_MembersInjector(mCarProvider);
  }

可以看到,主要是通过 Passerby_MembersInjector.create()new Passerby_MembersInjector()赋值,其中 create() 又是直接调用构造方法的。那这两个方法是调用了哪一个?谁调用的?这就要说到另外一个注解了: @Component

Dagger 的主要功能时依赖注入,从而达到解耦的目的。所以不会在Xxx_MembersInjector 中直接赋值,这样的话和 mCar = new Car() 没什么区别?所以我猜测,引入了 @Component 是为了达到依赖方和被依赖方不直接耦合的目的。但是,这样就造成了依赖方和被依赖方都与 @Component 耦合了。所以其实我也不太清楚 @Component 的具体作用

2019-02-12
@Component 限定了提供依赖的 Module 类,如果有过多个 Module 都提供该依赖,@Componentmodules 字段就指定了到底是哪个具体 Module 来完成这个依赖的提供。

@Component

@Inject 使用在成员上表示需要依赖对象,使用在构造器上表示提供自身对象。两者之间需要 @Component 注解作为依赖关系形成的桥梁。

@Component 使用在接口或抽象类上,编译后在 \build\generated\source\apt\debug\com\oliver\test 目录下生成一个名称为 Dagger + 被注解的类名称 的类。例如:

@Component
public interface Ofo {}

生成类名称: DaggerOfo

@Component 必须包含至少一个abstract component method,以下简称 CMCM 可以随意命名,但是必须有满足 Provider 或者 MembesInjector 约束的签名。

Provider Method :

Provider Method,以下简称 PM ,没有参数但是有返回值。返回一个 {@link Inject injected}{@link Provides provided} 类型,方法还可以被 @Qualifier 注解标注。也就是说,返回值必须是 被注入类型被提供类型

  • 被注入类型 表示其构造器被 @Inject 标注
  • 被提供类型 表示 @Component 包含的 @Module 中被 @Providers 注解标注的方法的返回值类型

注解 @Module@Providers 是什么?下面会说到。

MembersInjector Method :

MembersInjector Method ,以下简称 MMMM 有一个参数,并将依赖项注入每个 {@link Inject} 注解的字段和传递实例的方法,MM 返回 void, 为方便链式调用,也可返回 参数类型,。也就是说,参数类中有成员变量被 @Inject 标注,且该成员变量类的构造器也被 @Inject 标注。这样的话,当 @Compment 实现类【DaggerOfo】重写该方法【void inject(MainActivity activity)】时,就会通过成员变量相应生成的【Passerby_Factory】构造【Passerby】实例,赋值给参数【MainActivity】的成员变量【mPasserby】。具体如下:

public class Passerby {
    @Inject
    public Car mCar;

    public Passerby(){}

    @Inject
    public Passerby(Car car) {
        mCar = car;
        System.out.println("I'm a Passerby!");
    }
    public void go(){
        mCar.go();
    }
}

MainActivity 中使用:

public class MainActivity extends AppCompatActivity {

    @Inject
    Passerby mPasserby;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 注意,此处注入的参数this不能为null,
        DaggerOfo.builder().build().inject(this);
        mPasserby.go();
    }
}

开始使用 @Component 注解:

@Component
public interface Ofo {
    
//    Passerby getPasserby();
    
    // 使用 MembersInjector Method
    void inject(MainActivity activity);
}

在标注了 @Component 注解的类中使用 MM,生成类如下:

public final class DaggerOfo implements Ofo {
  private DaggerOfo(Builder builder) {}

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

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

  private Passerby getPasserby() {
    return injectPasserby(Passerby_Factory.newPasserby(new Car()));
  }

  @Override
  public void inject(MainActivity activity) {
    injectMainActivity(activity);
  }

  private Passerby injectPasserby(Passerby instance) {
    Passerby_MembersInjector.injectMCar(instance, new Car());
    return instance;
  }

  private MainActivity injectMainActivity(MainActivity instance) {
    MainActivity_MembersInjector.injectMPasserby(instance, getPasserby());
    return instance;
  }

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

    public Ofo build() {
      return new DaggerOfo(this);
    }
  }
}

可以看到,当我们调用 inject() 时,会调用到 Passerby_MembersInjector#injectMCar():

public static void injectMCar(Passerby instance, Car mCar) {
    // 直接赋值,假设传进来的 instance == null,报空指针就在所难免了
    instance.mCar = mCar;
}

调用 injectMainActivity(MainActivity) 之后,在层层调用,就达到了给成员变量 mPasserbyPasserby 的成员变量 mCar 的注入。

现在在 @Component 注解的类中使用 MP:

@Component
public interface Ofo {

    Passerby getPasserby();

//    void inject(Passerby passerby);
}

生成类 DaggerOfo 如下:

public final class DaggerOfo implements Ofo {
    private DaggerOfo(Builder builder) {}

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

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

    @Override
    public Passerby getPasserby() {
        return injectPasserby(Passerby_Factory.newPasserby(new Car()));
    }

    private Passerby injectPasserby(Passerby instance) {
        Passerby_MembersInjector.injectMCar(instance, new Car());
        return instance;
    }

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

        public Ofo build() {
            return new DaggerOfo(this);
        }
    }
}

可以看到,调用 getPasserby() 时会自动生成一个 Passerby 实例,然后给其注入依赖。外界可通过返回值获取到该实例。

总结

  • @Inject 使用在一个类的属性上,表示该类需要一个依赖;使用在一个类的构造方法上,表示由该构造方法提供依赖
  • @Component 注解作为依赖关系形成的桥梁,至少包含一个 CM。编译之后会生成 DaggerXxx
  • CM类型是 MM ,在类【假设为A】中使用 DaggerXxx ,则 A 中必须有 @Inject 注解标注的成员变量,用于赋值。因为经过上面生成的 DaggerOfo 来说,在 injectXxx() 中都是这样模板代码:instance.mXxx = Xxx_Factory.newXxx(),即赋值操作。
  • CM类型是 PM , 在类【假设为A】中使用 DaggerXxx 来获取需要注入的对象,然后在使用;例如:
Passerby mPasserby = DaggerOfo.builder().build().getPasserby();
mPasserby.go();

你可能感兴趣的:(走马观花-Dagger2 - @Inject 和 @Component)