Dagger2 源码分析

作者: 官先生Y | 来源:发表于2016-12-14 18:11 被阅读171次

    Dagger简单介绍

    Dagger2涉及到依赖注入,有关依赖注入的请到
    理解依赖注入

    通过注解方式实现依赖注入分为两种:

    • 在运行时读取注解来实现依赖注入,依赖的生成和注入需要依靠 Java 的反射机制。
    • 通过apt插件在编译阶段生成注入代码。

    Dagger2是属于后者,反射只是在编译阶段使用了,而在应用运行的时候其实运行的是真正的Java代码并没有涉及到注解反射。

    本文用一个极简的demo来说明Dagger原理,不去结合MVP模式使用Dagger方式,我自己认为这样会更加的复杂。

    Dagger编译阶段到底干了什么?

    有一个超简单的demo只有三个类分别是:MainActivity、MainComponent和PersonBean。

    三个类之间的关系

    Demo代码

    public class PersonBean {
    
        public String name;
    
        @Inject
        public PersonBean(){
        }
    }
    
    @Component
    public interface MainComponent {
        void inject(MainActivity activity);
    }
    

    写好PersonBean、MainComponent 代码后,使用as的build->make project,会生成DaggerMainComponent,在MainActivity上使用

    public class MainActivity extends AppCompatActivity {
    
        @Inject
        PersonBean personBean;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            DaggerMainComponent.builder().build().inject(this);
        }
    }
    

    上面使用了as的build->make project后,会在app/build/generated/source/apt目录下生成对应的注入代码。

    PersonBean - 》 PersonBean_Factory

    public enum PersonBean_Factory implements Factory<PersonBean> {
      INSTANCE;
    
      @Override
      public PersonBean get() {
        return new PersonBean();
      }
    
      public static Factory<PersonBean> create() {
        return INSTANCE;
      }
    }
    

    通过上面代码直观的看到PersonBean_Factory有两个方法:

    • get()
      在该方法中初始化了目标类需要依赖的PersonBean对象。

    • create()
      在该方法返回了PersonBean_Factory本类的实例。

    MainComponent-》DaggerMainComponent

    public final class DaggerMainComponent implements MainComponent {
      private MembersInjector<MainActivity> mainActivityMembersInjector;
    
      private DaggerMainComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      public static MainComponent create() {
        return builder().build();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.mainActivityMembersInjector =
            MainActivity_MembersInjector.create(PersonBean_Factory.create());
      }
    
      @Override
      public void inject(MainActivity activity) {
        mainActivityMembersInjector.injectMembers(activity);
      }
    
      public static final class Builder {
        private Builder() {}
    
        public MainComponent build() {
          return new DaggerMainComponent(this);
        }
      }
    }
    
    

    通过上面代码直观的看到:

    1. DaggerMainComponent对象是通过设计模式之构造器模式创建的
    2. DaggerMainComponent实现了MainComponent接口并实现了其中的inject()方法。

    MainActivity -》MainActivity_MembersInjector

    public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
      private final Provider<PersonBean> personBeanProvider;
    
      public MainActivity_MembersInjector(Provider<PersonBean> personBeanProvider) {
        assert personBeanProvider != null;
        this.personBeanProvider = personBeanProvider;
      }
    
      public static MembersInjector<MainActivity> create(Provider<PersonBean> personBeanProvider) {
        return new MainActivity_MembersInjector(personBeanProvider);
      }
    
      @Override
      public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.personBean = personBeanProvider.get();
      }
    
      public static void injectPersonBean(
          MainActivity instance, Provider<PersonBean> personBeanProvider) {
        instance.personBean = personBeanProvider.get();
      }
    }
    

    这里我们就有一些疑问:
    我们通过编译期间生成的这些类

    • 这些类之间的关系是怎样的?
    • 这些类中的方法如何被调用?
    • 一个完成的注入过程是怎么的?

    首先第一个问题,这些类之间的关系是怎样的?请看下面的UML类图

    Dagger的UML类图

    上面的第二三疑问,通过接下来分析dagger2依赖注入过程来理解,也就是代码执行流程。

    dagger2依赖注入过程

    DaggerMainComponent.builder().build().inject(this);
    

    首先我们从这一句代码为切入点,来学习dagger2依赖注入过程。

    1. DaggerMainComponent.builder()
      创建一个DaggerMainComponent内部的Builder对象并返回它。

    2. DaggerMainComponent.builder().build()
      创建一个DaggerMainComponent对象并返回它。这里我们知道DaggerMainComponent对象的实例化是通过构造器模式被创建的。

    DaggerMainComponent构造方法

    private DaggerMainComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
      }
    
    private void initialize(final Builder builder) {
    
        this.mainActivityMembersInjector =
            MainActivity_MembersInjector.create(PersonBean_Factory.create());
      }
    

    DaggerMainComponent构造函数干了这些事情:

    • 调用PersonBean_Factory.create()得到PersonBean_Factory对象,然后把此对象作为参数传入MainActivity_MembersInjector.create(...),然后MainActivity_MembersInjector.create方法创建
      MainActivity_MembersInjector实例对象并赋值,那么
      DaggerMainComponent就关联上了它。

    4.DaggerMainComponent.builder().build().inject(this);
    实际上是调用DaggerMainComponent.inject方法

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

    在这方法中使用在DaggerMainComponent构造方法中注入的MainActivity_MembersInjector对象,并调用其injectMembers方法。

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

    instance.personBean = personBeanProvider.get();这段代码很关键,目标类MainActivity依赖的类PersonBean就是在这时候被赋值的。personBeanProvider其实就是PersonBean_Factory。

    personBeanProvider.get()代码如下:

      @Override
      public PersonBean get() {
        return new PersonBean();
      }
    

    该方法创建一个被依赖的对象PersonBean并返回。

    这里我们就了解了Dagger2的依赖注入过程。

    相关文章

      网友评论

        本文标题:Dagger2 源码分析

        本文链接:https://www.haomeiwen.com/subject/iqtwmttx.html