dagger2之android源码解析(dagger-compiler你在哪)

引子(可忽略)
世界一词的来源,昨天突然想到了好像来源于佛教,于是特地google一番:一人一世界,大千世界。因为现代“世界”一词,导致我们对世界的理解过于狭隘。阿弥陀佛,罪过!!!

1.在AAC系列的GithubBrowserSample中有该案例案例中看到了dagger,按赖不住内心的好奇(第一次认真对待该源码,以前认为太麻烦,或者不想学,或者…),demo中的版本是2.16,目前已经被谷歌接收维护了,源码在此,注意了,你要是想看指定版本,例如我的是2.16,去2.16版本下载即可(下图送给和我一样“聪明”的人)

在这里插入图片描述

2.我也是看了很多天,从dagger2看到注解,从注解(原名叫控制反转,在200几年的时候被专家重新定义为注解,这里是真的专家,不服不行)看到反射,从反射有回到现在的dagger2。dagger源码解析,谷歌了N遍,都没有得到我要的答案:dagger2究竟是如何在build中生成对应的注解文件的,所有的回答都是一样的,哈,apt!!!还给我写了apt咋用,对我这么笨…咳咳,对我这么智慧的人给我
这些啥用,我不只是不会用,而且压根不知道dagger2中能complie(注解处理器,核心部分,如何生成build代码的)代码在哪好吧!!!过粪~

学习dagger2思路整理
1.网上找demo
这有一篇文章apt的使用:Android 利用 APT 技术在编译期生成代码
2.对照GithubBrowserSample中的用法,了解该项目中dagger2的实际使用;这里一篇文章有助于理解本demo:https://www.jianshu.com/p/f2977bf04c5e
3.对存在的疑问点自己谷歌(非常讨厌百度,但是没办法,被墙大就自己想办法);
4.最后源码学习;
以上是个人作为学习dagger2的一个思路,并非本章内容章节目录。

android引入dagger:

如下:这里build.gradle总共引入了5个dagger相关包:

build.gradle

	//这个是com.google.dagger:dagger:$versions.dagger
	implementation deps.dagger.runtime
	//这个是com.google.dagger:dagger-android:$versions.dagger
    implementation deps.dagger.android
    //这个是com.google.dagger:dagger-android-support:$versions.dagger
    implementation deps.dagger.android_support
 	...
	//com.google.dagger:dagger-compiler:$versions.dagger
    kapt deps.dagger.android_support_compiler
    //com.google.dagger:dagger-android-processor:$versions.dagger
    kapt deps.dagger.compiler
versions.gradle

def dagger = [:]
dagger.runtime = "com.google.dagger:dagger:$versions.dagger"
dagger.android = "com.google.dagger:dagger-android:$versions.dagger"
dagger.android_support = "com.google.dagger:dagger-android-support:$versions.dagger"
dagger.compiler = "com.google.dagger:dagger-compiler:$versions.dagger"
dagger.android_support_compiler = "com.google.dagger:dagger-android-processor:$versions.dagger"
deps.dagger = dagger

当我们项目构建后,如下图所示都是implementation 引入进来的,那么kapt的呢???
在这里插入图片描述

com.google.dagger:dagger-compiler在哪?com.google.dagger:dagger-android-processor:$versions.dagger在哪?这两个kapt(注解处理工具)呢?可能吧,我比较死板,我花费的功夫至少一半在这个上面了,网上到目前为止我也没找到谁说了这句话,我认为他们too yang too sample(大佬们:切,这么简单的问题不屑于写上去罢了!!!),还别说当满世界找不到shi,那都是最珍贵的,所以这个算本章 重点:
1.首先我们看com.google.dagger🗡2.16(另外两个implementation引入的雷同),代码如下:
在这里插入图片描述
我们再从github中提供的源码中也能找到对应的代码:
在这里插入图片描述
2.我们再看com.google.dagger:dagger-compiler和com.google.dagger:dagger-android-processor,我信你个鬼,毛都没有,我找了怀疑人生:最后。。。在generate_poms.py文件,该文件目录:dagger-dagger-2.16\util\maven,而且比较有意思,这个文件我看了最新的2.28.3版本没有,反正思路是这个,自己找。虽然python咱不熟,但是不妨碍我们去看,这里大致意思生成相应的文件夹目录,并且有别名。
在这里插入图片描述
来来来,咱验证下可对:我们去看下AppInjector文件中,有个DaggerAppComponent,该文件继承AppComponent,但是生成的“Dagger”+AppComponent在哪?

fun init(githubApp: GithubApp) {
        DaggerAppComponent.builder().application(githubApp)
            .build().inject(githubApp)
        githubApp
            .registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
                override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                    handleActivity(activity)
                }
		。。。
    }

文件的命名这里可以看出来见名知意,服!!!在\codegen文件夹中ComponentGenerator.java文件中,如下所示。问你服不服,不服吹的你一脸口水,再问你服不服以此do while操作,直到说服然后return;并继续下面的流程

static ClassName componentName(TypeElement componentDefinitionType) {
    ClassName componentName = ClassName.get(componentDefinitionType);
    return ClassName.get(componentName.packageName(), "Dagger" + classFileName(componentName));
  }

不得不说,大佬还是大佬,我在成为大佬的路上…没错,去找大佬,然后跪下…
包名,类,方法名,变量等的命名就可以看出一个人的水准,哎~~~

源码解析(终于到了只有痛苦,没有迷茫的时间段了)
声明:这篇根本不能算dagger的源码解析,真正涉及到源码部分我也只是按照自己的理解去随便提下,我理解的也非常模糊。感觉网上的真正说谷歌dagger源码的并没有,如果谁有,麻烦给我提供个地址,让我去认真学习一番,我说的是对照谷歌上dagger源码的解析。dagger源码涉及面(仅仅个人理解,因为我也不是很肯定,我相信后面肯定会深入去了解):python编程+gwt框架+grpc框架+javaoet(这个比较简单)+注解+android Framework等

一.dagger2如何为我们生成文件并放到build下
1.ComponentGenerator.java生成了Dagger+AppComponent(我们app中定义的文件):DaggerAppComponent.java
我们再看里面的局部代码片段(后面我相信我会详细写,这里我也并没有去系统理解,或者很多查找源码,自己就是根据它的命名找的,这里也体现了见名知意的好处),如下是DaggerAppComponent.java代码局部片段

@Override
    public AppComponent build() {
      if (appModule == null) {
        this.appModule = new AppModule();
      }
      if (application == null) {
        throw new IllegalStateException(Application.class.getCanonicalName() + " must be set");
      }
      return new DaggerAppComponent(this);
    }

对应于dagger中在哪里创建的?可以理一下,

private MethodSpec buildMethod() {
      MethodSpec.Builder buildMethod;
      if (builderSpec().isPresent()) {
        ExecutableElement specBuildMethod = builderSpec().get().buildMethod();
        // Note: we don't use the specBuildMethod.getReturnType() as the return type
        // because it might be a type variable.  We make use of covariant returns to allow
        // us to return the component type, which will always be valid.
        buildMethod =
            methodBuilder(specBuildMethod.getSimpleName().toString()).addAnnotation(Override.class);
      } else {
        buildMethod = methodBuilder("build");
      }
      buildMethod.returns(ClassName.get(graph.componentType())).addModifiers(PUBLIC);

      builderFields.forEach(
          (requirement, builderField) -> {
            switch (requirement.nullPolicy(elements, types)) {
              case NEW:
                buildMethod.addCode(
                    "if ($1N == null) { this.$1N = new $2T(); }", builderField, builderField.type);
                break;
              case THROW:
                buildMethod.addCode(
                    "if ($N == null) { throw new $T($T.class.getCanonicalName() + $S); }",
                    builderField,
                    IllegalStateException.class,
                    TypeNames.rawTypeName(builderField.type),
                    " must be set");
                break;
              case ALLOW:
                break;
              default:
                throw new AssertionError(requirement);
            }
          });
      buildMethod.addStatement("return new $T(this)", componentName);
      return buildMethod.build();
    }

首先在ComponentGenerator的write方法,该方法主要功能是编写DaggerXXComponent里面的具体方法,这里调用了ComponentWriter.writeComponent,

@Override
  Optional<TypeSpec.Builder> write(ClassName componentName, BindingGraph input) {
    return Optional.of(
        ComponentWriter.writeComponent(
            types, elements, keyFactory, compilerOptions, componentName, input));
  }

这里我不全看,仅仅看ComponentBuilder.create,这里面的代码及完成DaggerXXComponent中Builder的代码生成

static TypeSpec.Builder writeComponent(
     ...
    Optional<ComponentBuilder> builder =
        ComponentBuilder.create(name, graph, subcomponentNames, elements, types);
  
  		 ...
  }

2.GithubApp中定义了@Inject如下所示,首先声明一点该文件其实已经生了DispatchingAndroidInjector_Factory,因为这个注解是DispatchingAndroidInjector构造器中的注解,我只是想看看在那个类中生成的:SourceFiles.java的,实打实硬一个个文件找的!!!

@Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

这里声明一点,该dagger源码我没有在除了该代码自带注解以外的指引,所以只能一个个的搜,当然这里有些技巧,八仙过海各显神通了,我的技巧就是定位在codegen文件夹中,生成的代码如下,生成了xx_Factory文件:

/**
   * Returns the generated factory or members injector name for a binding.
   */
  static ClassName generatedClassNameForBinding(Binding binding) {
    switch (binding.bindingType()) {
      case PROVISION:
      case PRODUCTION:
        ContributionBinding contribution = (ContributionBinding) binding;
        switch (contribution.kind()) {
          case INJECTION:
          case PROVISION:
          case PRODUCTION:
            return elementBasedClassName(
                MoreElements.asExecutable(binding.bindingElement().get()), "Factory");

      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值