Dagger2 生成代码学习

  接上一篇文章介绍了Dagger2的初步使用,相信刚接触的人会觉得很奇怪,怎么会有很多自己没有定义的代码出现,为什么Component的创建方式是那样的。为了搞清楚这些东西,我们需要查看一下Dagger2 生成的源代码。Dagger2 是一个DI框架,通过学习生成的代码也可以更好的理解Dagger2是如何做依赖注入的。

  将上一篇文章中的工程在SublimeText中打开,结构如下图:

  可以看到AppComponent 生成了 DaggerAppComponent,Dagger2的生成规则中,我们自定义的Component生成之后会加上前缀“Dagger”。此外Module中的每个@Provides 方法都会生成一个Factory 类,命名规则也是很规律的。这里Dagger一共为我们生成了6个类:DaggerAppComponent / AppModule_ProvideApplicationFactory /ReposListActivity_MembersInjector / GithubApiModule_ProvideRetrofitFactory / GithubApiModule_ProvideOkHttpClientFactory / GithubApiModule_ProvideGitHubServiceFactory。接下来我们看看这些类具体是什么样的。

  首先来看一下DaggerAppComponent:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerAppComponent implements AppComponent {
  private Provider<Application> provideApplicationProvider;
  private Provider<OkHttpClient> provideOkHttpClientProvider;
  private Provider<Retrofit> provideRetrofitProvider;
  private Provider<GithubApiService> provideGitHubServiceProvider;
  private MembersInjector<ReposListActivity> reposListActivityMembersInjector;

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

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

  private void initialize(final Builder builder) {
    this.provideApplicationProvider = AppModule_ProvideApplicationFactory.create(builder.appModule);
    this.provideOkHttpClientProvider = GithubApiModule_ProvideOkHttpClientFactory.create(builder.githubApiModule);
    this.provideRetrofitProvider = GithubApiModule_ProvideRetrofitFactory.create(builder.githubApiModule, provideApplicationProvider, provideOkHttpClientProvider);
    this.provideGitHubServiceProvider = GithubApiModule_ProvideGitHubServiceFactory.create(builder.githubApiModule, provideRetrofitProvider);
    this.reposListActivityMembersInjector = ReposListActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideGitHubServiceProvider);
  }

  @Override
  public void inject(ReposListActivity activity) {
    reposListActivityMembersInjector.injectMembers(activity);
  }

  public static final class Builder {
    private AppModule appModule;
    private GithubApiModule githubApiModule;

    private Builder() {
    }

    public AppComponent build() {
      if (appModule == null) {
        throw new IllegalStateException("appModule must be set");
      }
      if (githubApiModule == null) {
        this.githubApiModule = new GithubApiModule();
      }
      return new DaggerAppComponent(this);
    }

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

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

  我们在Application中实例化AppComponent的时候是这样的:

appComponent = DaggerAppComponent.builder()
        .githubApiModule(new GithubApiModule())
        .appModule(new AppModule(this))
        .build();

  第一次见的时候肯定觉得一团雾水,为什么要这样写呢? 通过上面DaggerAppcomponent代码可以看出,使用了建造者模式。我们回顾一下AppComponent是怎么样的:

@Component(modules = { AppModule.class, GithubApiModule.class})
public interface AppComponent {
    // inject what
    void inject(ReposListActivity activity);
}

  @component 后面modules包含了两个类,在生成的DaggerAppComponent 中的内部类 Builder中,AppModule.class 和 GithubApiModule.class 成为了其成员,并且提供了set方法。在Application中实例化DaggerAppComponent的过程中其实就是调用了其set方法来设置依赖。此外在DaggerAppComponent各个@Provides 注解的方法返回类型都是其一个成员变量,并在Initialize()方法中创建。此外还有一个MembersInjector成员,DaggerAppComponent也要负责创建它。

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class ReposListActivity_MembersInjector implements MembersInjector<ReposListActivity> {
  private final MembersInjector<BaseActivity> supertypeInjector;
  private final Provider<GithubApiService> githubApiServiceProvider;

  public ReposListActivity_MembersInjector(MembersInjector<BaseActivity> supertypeInjector, Provider<GithubApiService> githubApiServiceProvider) {
    assert supertypeInjector != null;
    this.supertypeInjector = supertypeInjector;
    assert githubApiServiceProvider != null;
    this.githubApiServiceProvider = githubApiServiceProvider;
  }

  @Override
  public void injectMembers(ReposListActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    supertypeInjector.injectMembers(instance);
    instance.githubApiService = githubApiServiceProvider.get();
  }

  public static MembersInjector<ReposListActivity> create(MembersInjector<BaseActivity> supertypeInjector, Provider<GithubApiService> githubApiServiceProvider) {
      return new ReposListActivity_MembersInjector(supertypeInjector, githubApiServiceProvider);
  }
}

  ReposListActivity_MembersInjector 中通过 injectMembers 方法获取到 ReposListActivity 的实例(对应的就是 ReposListActivityComponent中的inject),然后进行赋值。从这种赋值的方式来看被@Inject注解的注入对象不能是private的。在看赋值是通过 githubAPiServiceProvider.get() 方法获取的,githubApiServiceProvider是一个工厂类,我们来看看这个工厂类是怎么样的:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class GithubApiModule_ProvideGitHubServiceFactory implements Factory<GithubApiService> {
  private final GithubApiModule module;
  private final Provider<Retrofit> retrofitProvider;

  public GithubApiModule_ProvideGitHubServiceFactory(GithubApiModule module, Provider<Retrofit> retrofitProvider) {
    assert module != null;
    this.module = module;
    assert retrofitProvider != null;
    this.retrofitProvider = retrofitProvider;
  }。

  @Override
  public GithubApiService get() {
    GithubApiService provided = module.provideGitHubService(retrofitProvider.get());
    if (provided == null) {
      throw new NullPointerException("Cannot return null from a [email protected] @Provides method");
    }
    return provided;
  }

  public static Factory<GithubApiService> create(GithubApiModule module, Provider<Retrofit> retrofitProvider) {
    return new GithubApiModule_ProvideGitHubServiceFactory(module, retrofitProvider);
  }
}

  GithubApiModule_ProvideGitHubServiceFactory 类中有两个成员,一个是提供(@Provides)GithubService 所在的 module 类,一个是创建GithubService方法所需参数的retrofitProvider(从这里可以看出Dagger2需要创建retrofitProvider的工厂)。然后通过 module.provdeGitHubService()方法来创建 GithubApiService实例,这样最终穿件了在ReposListActivity中注入的依赖实例。

  Dagger2 入门有点绕,也没找到什么系统性的资料,但是可以通过查看框架自动生成的类来加深理解,方便大家使用。使用到dependencies和SubComponent注解的时候生成的代码就比较多了,本来也想捋捋的,但是原理和上面的都是一样的,大家自己去看吧。

时间: 2024-12-16 07:33:14

Dagger2 生成代码学习的相关文章

【MyBatis学习15】MyBatis的逆向工程生成代码

1. 什么是逆向工程 mybatis的一个主要的特点就是需要程序员自己编写sql,那么如果表太多的话,难免会很麻烦,所以mybatis官方提供了一个逆向工程,可以针对单表自动生成mybatis执行所需要的代码(包括mapper.xml.mapper.Java.po..).一般在开发中,常用的逆向工程方式是通过数据库的表生成代码. 2. 使用逆向工程 使用mybatis的逆向工程,需要导入逆向工程的jar包,我用的是mybatis-generator-core-1.3.2,已经上传到下载频道了(点

Android注解使用之通过annotationProcessor注解生成代码实现自己的ButterKnife框架

前言: Annotation注解在Android的开发中的使用越来越普遍,例如EventBus.ButterKnife.Dagger2等,之前使用注解的时候需要利用反射机制势必影响到运行效率及性能,直到后来android-apt的出现通过注解根据反射机制动态编译生成代码的方式来解决在运行时不再使用发射机制,不过随着android-apt的退出不再维护,我们今天利用Android studio的官方插件annotationProcessor来实现一下自己的ButterKnife UI注解框架. 需

使用 Velocity 模板引擎快速生成代码

原文地址:http://www.ibm.com/developerworks/cn/java/j-lo-velocity1/ Velocity 是一个基于 Java 的模板引擎,它允许任何人仅仅简单的使用模板语言来引用由 Java 代码定义的对象,从而实现界面和 Java 代码的分离,使得界面设计人员可以和 Java 程序开发人员同步开发一个遵循 MVC 架构的 web 站点.但是在实际应用过程中,Velocity 又不仅仅被用在了 MVC 的架构中. Velocity 模板引擎介绍 在现今的软

公益图书馆-Contribute捐赠-代码学习

1.ContributeController.class.php 控制器 <?php /** * Created by PhpStorm. * User: lxd * Date: 14-7-27 * Time: 下午2:43 */ namespace Home\Controller; class ContributeController extends SyController{ /**@author lxd * @description 首页 */ public function index(

Java进阶之 如何自动生成代码

一.前言:为什么要有代码的自动生成? 对于这个问题 最简洁直接的回答就是:代替手动编写代码.提高工作效率. 什么样的场景和代码适合用自动生成这种方式呢? 做过Java服务端的朋友一定都知道代码中我们需要编写与数据库表映射的Java实体类(Entity).需要编写与实体对应的DAO类(XxDao.java类中有包含对应实体的增.删.改.查基本操作).在这些实体类中通常都是一些属性方法以及属性对应的get/set方法.而实体对应的DAO类中也基本会包含有增.删.改.查这些与数据库操作相关的方法.在编

(转)MyEclipse注册码生成代码

(本文出处转自http://www.blogjava.net/lishunli/archive/2010/01/07/308616.html) MyEclipse注册码网上到处都是,但是你想不想用你的名字来进行注册,而且想不想知道MyEclipse注册码到底是如何生成的?现在就让我来带你看看MyEclipse注册码是如何人性化的生成的. 代码如下: package org.usc.key.gen; import java.io.BufferedReader; import java.io.IOE

回顾一下MyBatis逆向工程——自动生成代码

前言 最近做的项目(SSM+Shiro)的数据库表已经创建完成,一共有15张表,如果我们一个个去写pojo/bean的代码以及各种sql语句的话未免太过麻烦而且很容易出错,这个时候我们就需要MyBatis逆向工程去为我们生成这些基本的东西.先来简单的了解一下什么是逆向工程 一 什么是逆向工程 官网解释浓缩版:MyBatis逆向工程需要用到的就是MyBatis官方提供的MyBatis Generator(MBG).MBG是MyBatis和iBATIS的代码生成器,它将为所有版本的MyBatis以及

idea中mybatis generator自动生成代码配置 数据库是sqlserver

好长时间没有写博客了,最近公司要用java语言,开始学习java,属于初学者,今天主要记录一下mybatis generator自动生成代码,首先在如下图的目录中新建两个文件,如下图 generatorConfig.xml and jdbc.properties都要放在resource根目录下 具体generatorConfig.xml内容如下: <?xml version="1.0" encoding="UTF-8"?>   <!DOCTYPE

一个女大学生的代码学习之路(二)

首先说一下,写这种文章是由于我在四月四日晚上,在手动搭建自己的第一个ssh项目的时候,遇到了一个配置的问题,怎么解决也弄不好,当时是四号晚上九点,我看了一眼表,我就想两个小时之内,我要是能搞定就算行了,但是其实,我搞到三点才OK(凌晨),那时候已经是五号了,转天是一家子去扫墓的时候,结果我居然以这种一个理由没有去,理由是我太累了么?我只是就是搭了一个架子,就是由于我的包太混乱了,导致不兼容,所以tomcat总也不启动,你可能认为好笑,这么简单一个问题怎么就费这多多时间呢,但是作为一个刚接触三框架