DI理解以及Dagger生成代码分析

前言

依赖注入是我在安卓项目架构学习(dagger+mvp+retrofit+rxjava+eventbus)里面的又一大步。通过一天多的系统学习(看别人的项目源码,博客文章,自己看dagger的生成源码),差不多也可以去自己总结一下了。dagger2的用法网上太多教程了,我就不再描述了。这里我只总结依赖注入的概念,在项目架构中的作用以及部分最基础的生成源码个人分析。建议大家在学习dagger之前先去学习java注解和反射,因为dagger确实不好理解,如果有了注解基础学习起来会更轻松。

以前看人家大牛的项目都有个inject包,以前想当然的以为就是个注解包。。也不懂里面的component和module包是干嘛的。现在想想,也又算一种进步吧!

大家可以通过我这个练手app巩固dagger的用法 :githubQuery

依赖注入?(DI and IOC)

其实依赖注入也是为了模块解耦,你会发现一切一切,不论是mvp还是dagger都是为了模块解耦。dagger和mvp结合起来还可以做到把m-v-p之间进一步解耦。所谓耦合就是两个模块联系在了一起,什么意思呢?比如一个模块A里面new了另一个模块B的对象,这时候就说两个模块耦合在了一起,如果现在B模块的构造函数做了修改,那么你还需要去修改模块A里面的代码。而我们希望的是B无论怎么修改都不会影响模块A。(联系mvp模式,无论m层怎么修改,都不会影响v层)而依赖注入可以用两种方法来解决:

1.传递依赖:

class A{
  //...
  B b;
  public A(B b){
  this.b = b;
  }
}

或者传递给 B的更高层级的抽象层(面向接口编程的思想)。

2.注入依赖。(如dagger di框架)

其实这种解决办法就叫做控制反转(ioc)。把添加依赖的权利给外部,自己不去主动添加依赖关系

好像有人分不大清楚dagger和butterknife有啥区别。。其实区别很大,butterkinfe也是通过注解来实现依赖注入,不过他做的是view的依赖注入。而dagger做的是更高层次的模块之间的依赖注入。

话说以前还写了一个很简单的view依赖注入框架(用的反射),我记得我以前在github上面写的是依赖注入框架,后来赶紧改成了view依赖注入框架。。

依赖注入器?

如果说用传递依赖的话,那么如果模块A需要模块B的大量对象,或者说依赖程度很高,那么传递函数里面的依赖参数将会很多。

而使用注入器可以极大的减少代码量,模块之间的依赖关系也会很清晰。把注入器看作项目的一个模块(inject)专门负责把某些模块注入到他的依赖中去。当然说这些你可能还是不能体会到它的好处,多去写写,看看人家的项目代码才能慢慢体会。(比如我把所有的基础配置以及application的context全部提供在applicaion的module,然后直接把这个module注入到baseactivity或者application中去,然后其他的activity module再去继承这个application module。一行代码就去注入很多的依赖!)

Dagger2

dagger2就是现在一个比较火的依赖注入器框架。它使用的预编译期间生成代码完成依赖,而不是用的反射。。都知道反射对手机应用开发影响是比较大的。我学习这个框架就把它想成了一个注射器,component是针管,module是注射瓶,里面的依赖对象是注入的药水,build方法是插进患者,inject方法的调用是推动活塞。这样形象的理解还是很容易理解的!!

dagger需要掌握的就是component, module, scope, provides, singleton.

下面来探讨部分生成源码吧。


描述:我现在有两个medule,并且其中一个component依赖另一个component。代码如下

/**
 * Created by Zane on 16/1/21.
 */
@Module
public class ActivityModule {
    @Provides
    UserModel provideUserModel(){
        return new UserModel();
    }
}

@Module
public class ActivityModule2 {
    @Provides
    UserModelTwo provideUserModelTwo(){
        return new UserModelTwo();
    }
}

@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    //void inject(Activity activity);
    UserModel userModel();
}

@Component(dependencies = ActivityComponent.class, modules = ActivityModule2.class)
public interface ActivityComponent2 {
    void inject(MainActivity activity);
}

两个model/bean代码如下:

/**
 * Created by Zane on 16/1/21.
 */
public class UserModel {

    private String name = "xuzhi";
    private String age = "20";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

public class UserModelTwo {

    private String phone = "1888";

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

在activity中的注入代码如下:

activityComponent = DaggerActivityComponent
                                    .builder()
                                    .activityModule(new ActivityModule())
                                    .build();
activityComponent2 = DaggerActivityComponent2
                                     .builder()
                                     .activityComponent(activityComponent)
                                     .activityModule2(new ActivityModule2())
                                     .build();
activityComponent2.inject(this);

我们都知道,编译之后dagger框架会自动给我们生成以dagger+xxxcomponent为名的类。如我的代码就是生成了DaggerActivityComponent类,并且通过一系列的方法调用最终构建成功。看过生成代码的人会感觉他用的就是包装器模式!我们首先来看DaggerActivityComponent的builder()方法:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent implements ActivityComponent {
  private Provider provideUserModelProvider;

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

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

可以看到生成了一个Provider provideUserModelProvider;,而在这个组件所对应的模块里面我们提供了user model的对象。DaggerActivityComponent的构造器先不管。一步步来,我们看到builder()方法return了一个Builder类型的对象,往下看你就会看到Builder这个静态内部类!代码如下:

public static final class Builder {
    private ActivityModule activityModule;

    private Builder() {
    }

    public ActivityComponent build() {
      if (activityModule == null) {
        this.activityModule = new ActivityModule();
      }
      return new DaggerActivityComponent(this);
    }

    public Builder activityModule(ActivityModule activityModule) {
      if (activityModule == null) {
        throw new NullPointerException("activityModule");
      }
      this.activityModule = activityModule;
      return this;
    }
  }

注入代码中,我们紧接着调用了activityModule(ActivityModule activityModule)方法。我们看到因为在ActivityComponent中我们用@component添加了ActivityModule。所以这里生成了这样一个方法来让你传递一个对象进来。之后我们调用了build()方法,这个方法里面调用了DaggerActivityComponent类的构造方法!

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

这里也没啥看的,继续看initialize(builder);方法:

private void initialize(final Builder builder) {
    this.provideUserModelProvider =     ActivityModule_ProvideUserModelFactory.create(builder.activityModule);
  }

这里有个新类,叫做xxxxFactory,这个类很重要,点进去继续看creat方法:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class ActivityModule_ProvideUserModelFactory implements Factory {
  private final ActivityModule module;

  public ActivityModule_ProvideUserModelFactory(ActivityModule module) {
    assert module != null;
    this.module = module;
  }

  @Override
  public UserModel get() {
    UserModel provided = module.provideUserModel();
    if (provided == null) {
      throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
    }
    return provided;
  }

  public static Factory create(ActivityModule module) {
    return new ActivityModule_ProvideUserModelFactory(module);
  }
}

很简单,就是把我们的ActivityModule存在了这个类里面,并提供一个get方法,这个get方法之后会用到。

DaggerActivityComponent类的代码我们就看完了,很简单,因为这个针头并没有提供inject方法哈哈,而是多重依赖给了ActivityComponent2.接下来看DaggerActivityComponent2的代码:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent2 implements ActivityComponent2 {
  private Provider userModelProvider;
  private Provider provideUserModelTwoProvider;
  private MembersInjector mainActivityMembersInjector;

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

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

第一个module中的usermodel也被注入到了第二个module中!接着看Builder类

public static final class Builder {
    private ActivityModule2 activityModule2;
    private ActivityComponent activityComponent;

    private Builder() {
    }

    public ActivityComponent2 build() {
      if (activityModule2 == null) {
        this.activityModule2 = new ActivityModule2();
      }
      if (activityComponent == null) {
        throw new IllegalStateException("activityComponent must be set");
      }
      return new DaggerActivityComponent2(this);
    }

    public Builder activityModule2(ActivityModule2 activityModule2) {
      if (activityModule2 == null) {
        throw new NullPointerException("activityModule2");
      }
      this.activityModule2 = activityModule2;
      return this;
    }

    public Builder activityComponent(ActivityComponent activityComponent) {
      if (activityComponent == null) {
        throw new NullPointerException("activityComponent");
      }
      this.activityComponent = activityComponent;
      return this;
    }
  }

ActivityModule2 activityModule2,ActivityComponent activityComponent;都是这个类的静态变量,因为一个是依赖一个是对应的 module。然后你可以自己看看注入代码,我们确实是分别调用了activityComponent(ActivityComponent activityComponent),activityModule2(ActivityModule2 activityModule2)之后才去调用build();

private void initialize(final Builder builder) {
    this.userModelProvider = new Factory() {
      private final ActivityComponent activityComponent = builder.activityComponent;
      @Override public UserModel get() {
        UserModel provided = activityComponent.userModel();
        if (provided == null) {
          throw new NullPointerException("Cannot return null from a non-@Nullable component method");
        }
        return provided;
      }
    };
    this.provideUserModelTwoProvider = ActivityModule2_ProvideUserModelTwoFactory.create(builder.activityModule2);
    this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), userModelProvider, provideUserModelTwoProvider);
  }

最上面有一段代码,其用意相当于重新构建一个xxxxFactory类。你可以看到之前那个xxxFactory类是实现了Factory接口,而这里则是用匿名内部类做到了,为什么要这么做呢,我认为是因为这个变量是继承过来的,所以不应该再去重复creat而是通过activitycomponent来调用userModel()方法来获得。然后我们就把两个成员变量都初始化了!之后再来看注入,我们点到MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), userModelProvider, provideUserModelTwoProvider);方法去看:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector {
  private final MembersInjector supertypeInjector;
  private final Provider modelProvider;
  private final Provider model2Provider;

  public MainActivity_MembersInjector(MembersInjector supertypeInjector, Provider modelProvider, Provider model2Provider) {
    assert supertypeInjector != null;
    this.supertypeInjector = supertypeInjector;
    assert modelProvider != null;
    this.modelProvider = modelProvider;
    assert model2Provider != null;
    this.model2Provider = model2Provider;
  }

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    supertypeInjector.injectMembers(instance);
    instance.model = modelProvider.get();
    instance.model2 = model2Provider.get();
  }

  public static MembersInjector create(MembersInjector supertypeInjector, Provider modelProvider, Provider model2Provider) {
      return new MainActivity_MembersInjector(supertypeInjector, modelProvider, model2Provider);
  }
}

很清楚了,也是一种包装器模式。我们可以类比,每一个被注入的类都会生成一个xxx_MembersInject类。看到我们把两个Factory对象都传进来了,并且调用了get方法来获得我们需要注入的依赖对象。大功告成,最后看DaggerActivityComponent2里面的最后一个方法:

@Override
  public void inject(MainActivity activity) {
    mainActivityMembersInjector.injectMembers(activity);
  }

对!就是我们MainActivity里面调用的inject()方法。对应上一份源码看,懂了吧!这就是注入过程,所以我把inject()方法的调用比做活塞的推动。


所以看了这么多,其实就是想多了解一下dagger如何运作,我们的调用代码tmd为什么要这么写。嗯,就是这样!之前学这个也是越看越烦啦,后来慢慢的总结一下也是极好的。下面就准备开始用mvp+dagger2+rxjava+retrofit来搞点事情了。并且我还不准备用我自己的mvp框架,感觉写的太渣了,分分钟爆炸的节奏。。

未经博主同意,不得转载该篇文章

你可能感兴趣的:(DI理解以及Dagger生成代码分析)