Dagger2注入原理简单分析

原创 2017年01月12日 12:25:57

写在前面

本文适合接触过,或者已经使用了一段dagger2的小伙伴加深印象,或者想要深入的了解关于dagger2如何进入DI(dependencies inject)过程的一个简单的分析,起到抛砖引玉的作用.

如果你还不知道Dagger2是什么的话,建议去Google 百度 一下.这里就不赘述了,好多好多资料..

重点类

  • Provider
  • Factory
  • MembersInjector

前两个接口其实是一个东西. Factory 继承了 Provider 内部只存在1个方法 get();究其根本,从字面意思上理解就是提供者.它们是泛型借口,get()方法的返回值也同样是该泛型.这里我们可以做一下猜测,它返回的应该是需要注入的类.

MembersInjector 同样也是一个接口,内部也是只有一个方法
injectMembers(T instance) 很直白,直面理解就是成员注入,猜测这个的作用是对于目标累的注入,而T则是目标类.


编译后生成的源码路径结构如下

这里写图片描述

编译生成的累并不多.

为了防止迷惑.下面讲简单的贴出dagger2的配置过程,如果小伙伴们对这个配置已经很熟悉的话请忽略下面,直接跳到分析原理的过程

这里写图片描述


AppComponent

@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
    Context getContext();
}

AppModule

@Module
public class AppModule {

    private Application appContext;

    public AppModule(App app) {
        this.appContext = app;
    }

    @Provides
    @Singleton
    public Context provideContext() {
        return appContext;
    }
}

App

public class App extends Application {

    private static App INSTANCE;
    @Override
    public void onCreate() {
        super.onCreate();
        INSTANCE = this;

    }

    public static AppComponent getAppComponent() {
       AppComponent appComponent =  DaggerAppComponent.builder()
                .appModule(new AppModule(INSTANCE))
                .build();

        return appComponent;
    }
}

ActivityComponent

@ActivityScope
@Component(dependencies = AppComponent.class,modules = ActivityModule.class)
public interface ActivityComponent {

    void inject(MainActivity mainActivity);

}

ActivityModule

@Module
public class ActivityModule {

    private Activity activity;

    public ActivityModule(Activity activity) {
        this.activity = activity;
    }

    @Provides
    @ActivityScope
    public Context provideContext() {
        return activity;
    }

    @Provides
    @ActivityScope
    public Person providePerson() {
        return new Person();
    }
}

MainActivity

public class MainActivity extends AppCompatActivity {

    @Inject Person p;
    private TextView textView;


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

    private void injectActivity() {
        ActivityComponent activityComponent = DaggerActivityComponent
                .builder()
                .appComponent(App.getAppComponent())
                .activityModule(new ActivityModule(this))
                .build();

        activityComponent.inject(this);
    }

    private void initView() {
        textView =(TextView)findViewById(R.id.tv_daggertest);
        textView.setText(p.toString());
    }
}

Person

public class Person {


    private String name = "张三";
    private int age = 26;

    public Person() {
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

代码不多.配置起来也很简单. 运行结果如下
这里写图片描述

好了.下面开始步入正题,证实我们上面的猜测.这里我们直接从Activity的注入开始.因为App种并不需要注入.只需要提供AppComponent

public final class DaggerActivityComponent implements ActivityComponent {
  private Provider<Person> providePersonProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

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

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

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

    this.providePersonProvider =
        DoubleCheck.provider(ActivityModule_ProvidePersonFactory.create(builder.activityModule));

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(providePersonProvider);
  }

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

  public static final class Builder {
    private ActivityModule activityModule;

    private AppComponent appComponent;

    private Builder() {}

    public ActivityComponent build() {
      if (activityModule == null) {
        throw new IllegalStateException(ActivityModule.class.getCanonicalName() + " must be set");
      }
      if (appComponent == null) {
        throw new IllegalStateException(AppComponent.class.getCanonicalName() + " must be set");
      }
      return new DaggerActivityComponent(this);
    }

    public Builder activityModule(ActivityModule activityModule) {
      this.activityModule = Preconditions.checkNotNull(activityModule);
      return this;
    }

    public Builder appComponent(AppComponent appComponent) {
      this.appComponent = Preconditions.checkNotNull(appComponent);
      return this;
    }
  }
}

这个类是配置后AS编译后生成的.名称是固定的DaggerActivityComponent就是在自定义的 XXXComponent前面加上Dagger ,其实就是他的实现类,实现了你在Component中定义的所有方法,和通常的接口实现类并没有说明去区别.
在它的内部,IDE帮我们生成了下面2个成员变量

  • private Provider<Person> providePersonProvider;
  • private MembersInjector<MainActivity> mainActivityMembersInjector;

并在构造函数中进行初始化

private void initialize(final Builder builder) {

    this.providePersonProvider =
        DoubleCheck.provider(ActivityModule_ProvidePersonFactory.create(builder.activityModule));

    this.mainActivityMembersInjector = MainActivity_MembersInjector.create(providePersonProvider);
  }

在前面也提到了这2个对象的一些作用,一个是提供,一个是注入,
Provider<Person> 是提供所需要的Person对象,初始化providePersonProvider后传递到mainActivityMembersInjector种,注入目标类,下面看一下这2个类的具体实现

ActivityModule_ProvidePersonFactory

public final class ActivityModule_ProvidePersonFactory implements Factory<Person> {
  private final ActivityModule module;

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

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

  public static Factory<Person> create(ActivityModule module) {
    return new ActivityModule_ProvidePersonFactory(module);
  }
}

通过Create方法传递对应提供的配置的module注入到类中,然后在get方法种返回得到的Person实例,其实这里调用的module.providePerson()就是在ActivityModule种用@Provider标识的providePerson()方法

MainActivity_MembersInjector

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<Person> pProvider;

  public MainActivity_MembersInjector(Provider<Person> pProvider) {
    assert pProvider != null;
    this.pProvider = pProvider;
  }

  public static MembersInjector<MainActivity> create(Provider<Person> pProvider) {
    return new MainActivity_MembersInjector(pProvider);
  }

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

  public static void injectP(MainActivity instance, Provider<Person> pProvider) {
    instance.p = pProvider.get();
  }
}

因为在DaggerActivityCompon的构造函数中ActivityModule_ProvidePersonFactory的实例已经传递到了mainActivityMembersInjector中,也就是说,其实这两个类已经形成了依赖关系,这里

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

这个方法其实就是给Activity种用@Injcet标识的Person对象进行赋值,这个方法其实就是在DaggerActivityComponent中调用的,这样一来,所有的注入关系,初始化关系就形成了.


到这里.dagger2的注入原理就分析完成了,总结一下

IDE帮助我们生成的以Dagger开头的类,实现了我们自定义的XXXComponent,并在构造方法中初始化了Provider和MembersInjector的实现类的实例,并把Provider的实例传入MembersInjector中,形成依赖关系.然后通过Provider的实现类中的get方法获取自定义的Module中配置的实例,在MembersInjector的injectMembers方法中完成对目标类注入依赖类的初始化工作.

版权声明:本文为博主原创文章,未经博主允许不得转载。

Dagger2实现依赖注入之一步一步带你入门

一、首先你要知道什么是依赖? 想要理解Dagger2,首先你要理解一个概念,就是什么是依赖,懂的同学可以省过此段。这里给大家举个通俗易懂的例子,让你秒懂什么是依赖,你今天去办港澳通行证,出入境告诉...
  • Interface_l
  • Interface_l
  • 2017年04月10日 14:21
  • 573

Dagger2注入原理解析

在上篇博客中我们介绍了Dagger2该如何在项目中使用,这篇博客将继续分析Dagger2实现的原理,代码依然采用上篇的代码,看这里。Dagger2的注入原理原理的讲解我们通过小明来带我们学习。小明在看...
  • study_zhxu
  • study_zhxu
  • 2016年08月12日 15:29
  • 4286

依赖注入框架dagger2的@Scope注解初探(根据生成的源码进行分析)

依赖注入框架dagger2的@Scope注解初探(根据生成的源码进行分析)
  • u013262051
  • u013262051
  • 2016年04月29日 20:55
  • 533

Dagger2从0基础使用,到单例注入的正确姿势

Dagger2从0基础使用,到单例注入的正确姿势 环境搭建 基本流程 四个基础注解 @Inject @Module @Provides @Component ...
  • lmj121212
  • lmj121212
  • 2017年03月31日 10:28
  • 890

简单总结下常用的注入姿势

简单总结下常用的注入姿势
  • u013761036
  • u013761036
  • 2017年01月01日 20:21
  • 1055

用Dagger2在Android中实现依赖注入

转自:http://www.cnblogs.com/sunshine-anycall/p/5363301.html 依赖注入这个模式(模式已经用烂了,这里再烂一次)是用来给应用的各部...
  • huanghailang
  • huanghailang
  • 2016年06月24日 11:36
  • 567

使用Dagger 2进行依赖注入 - API介绍

Dagger 2 依赖注入
  • lihenair
  • lihenair
  • 2016年05月16日 14:32
  • 2746

sql注入攻击详解(原理理解)

前段时间,在很多博客和微博中暴漏出了12306铁道部网站的一些漏洞,作为这么大的一个项目,要说有漏洞也不是没可能,但其漏洞确是一些菜鸟级程序员才会犯的错误。其实sql注入漏洞就是一个。作为一个菜鸟小程...
  • qq_36617521
  • qq_36617521
  • 2016年12月14日 08:17
  • 2145

依赖注入的原理

什么是依赖注入依赖注入是实现程序解耦的一种方式。如果通过百度搜索可以找到如下答案: 控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序...
  • lisdye2
  • lisdye2
  • 2016年07月12日 11:26
  • 3979

spring的依赖注入和工作原理

1、设置注入 IoC容器使用setter方法来注入被依赖的实例 2、构造注入 构造实例,完成依赖实例的初始化。 --> 创建实例时机不同 设置注入,先通过无参构造器创建一个调用者实例,在调...
  • u011513323
  • u011513323
  • 2014年07月29日 15:58
  • 5897
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Dagger2注入原理简单分析
举报原因:
原因补充:

(最多只允许输入30个字)