Dagger2源码剖析
2016-07-28 15:59
405 查看
Dagger2源码剖析
Dagger是一个非常优秀的IOC框架,使用Dagger能够极大减少代码耦合,介绍Dagger如何使用的文章网上有很多,在这里给大家推荐3篇,作者讲得非常白话,大家应该可以理解:Android:dagger2让你爱不释手-基础依赖注入框架篇
Android:dagger2让你爱不释手-重点概念讲解、融合篇
Android:dagger2让你爱不释手-终结篇
在使用过Dagger之后,大家不免会对其实现原理产生疑问,本文就对Dagger的源码进行剖析。(由于dagger代码并未开源,一些细节方面的东西可能讲不到)
首先Dagger是基于APT开发的,所以请大家先看下我之前写的一篇文章
编译期注解浅析
好的,终于完成了系列的准备工作,
接下来咱们还是沿着我上篇文章中提到的编译期注解的三要素,一一剖析Dagger框架
注解
dagger里面常用的注解无非就是
@Inject
@Moudel
@Component
@Qualifier
@Scope
@Target({ METHOD, CONSTRUCTOR, FIELD }) @Retention(RUNTIME) @Documented public @interface Inject {}
@Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented public @interface Qualifier {}
@Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documented public @interface Scope {}
这3个注解不来自dagger,而来自java本身!,通过这些注解的源码我们关键要捕获一个信息,这些注解在哪里使用,可以看到Inject可以在方法,构造方法,属性上面使用,而Qualifier和Scope则只能在注解上面使用(意味着我们不能直接使用他们,所以就有了@Name @Singleton这些注解)
再看看dagger自己写的注解
@Retention(RUNTIME) @Target(TYPE) @Documented public @interface Component { Class<?>[] modules() default {}; Class<?>[] dependencies() default {}; }
Component注解在类上,可以包含多个Modules,也可以依赖多个Component.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Module { Class<?>[] includes() default {}; }
Module也是注解在类上
@Documented @Target(METHOD) @Retention(RUNTIME) public @interface Provides { enum Type { UNIQUE, SET, SET_VALUES; } Type type() default Type.UNIQUE; }
在@Provides这个里面需要注意的是”SET”的这个设置,这个是什么意思呢?如果你选择了”UNIQUE”(其实就是不选)。那么别人一需要这个对象就会来你这里找(必须是唯一的,除了Inject(因为他们优先级不同)),但使用了SET后,你其实就是把生产出来的对象扔到一个对象池里,需要的时候从池里面拿。(这个是个人理解,如果有误,这块请大家私信我,我也好好学习学习)。
处理注解的类
apt 'com.google.dagger:dagger-compiler:{version}'
这也是我们为什么需要在Build.gradle里面加上这句话的原因,因为我们需要他们在编译期生成代码
整个Dagger的流程其实就是一个画图的过程,将能够提供对象的类于需要对象的类画在一张图上,这样就实现了所谓依赖注入
接下来我们看一下处理注解的类:
首先,我们必须找到注解的入口
@AutoService(Processor.class) public final class ComponentProcessor extends BasicAnnotationProcessor {}
没错,只是这个类(当然里面有很多方法),包括上面的注解分析,还有这里处理注解的类,如果你找的和我不一样,那说明你是在看dagger1,github上只有1
这个类会生成怎么样的代码呢?
@Generated("dagger.internal.codegen.ComponentProcessor") public final class DaggerAppComponent implements AppComponent { private Provider<HRApp> provideApplicationProvider; private DaggerAppComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } private void initialize(final Builder builder) { this.provideApplicationProvider = ScopedProvider.create(AppModule_ProvideApplicationFactory.create(builder.appModule)); } @Override public HRApp getApplication() { return provideApplicationProvider.get(); } public static final class Builder { private AppModule appModule; private Builder() { } public AppComponent build() { if (appModule == null) { throw new IllegalStateException("appModule must be set"); } return new DaggerAppComponent(this); } public Builder appModule(AppModule appModule) { if (appModule == null) { throw new NullPointerException("appModule"); } this.appModule = appModule; return this; } } }
@Generated("dagger.internal.codegen.ComponentProcessor") public final class AppModule_ProvideApplicationFactory implements Factory<HRApp> { private final AppModule module; public AppModule_ProvideApplicationFactory(AppModule module) { assert module != null; this.module = module; } @Override public HRApp get() { HRApp provided = module.provideApplication(); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method"); } return provided; } public static Factory<HRApp> create(AppModule module) { return new AppModule_ProvideApplicationFactory(module); } }
这个是component和module生成的代码,module其实就是生成一个产生对象的工厂。每次需要对象的时候,现在看到了吧,为什么我们的component要用接口,因为dagger要实现它。现在情况是module生成的类提供对象,component拿到这个对象然后注入到需要它的对象中,然而怎么知道谁需要呢?
@Generated("dagger.internal.codegen.ComponentProcessor") public final class BaseActivity_MembersInjector implements MembersInjector<BaseActivity> { private final MembersInjector<AppCompatActivity> supertypeInjector; private final Provider<HRApp> applicationProvider; public BaseActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<HRApp> applicationProvider) { assert supertypeInjector != null; this.supertypeInjector = supertypeInjector; assert applicationProvider != null; this.applicationProvider = applicationProvider; } @Override public void injectMembers(BaseActivity instance) { if (instance == null) { throw new NullPointerException("Cannot inject members into a null reference"); } supertypeInjector.injectMembers(instance); instance.application = applicationProvider.get(); } public static MembersInjector<BaseActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<HRApp> applicationProvider) { return new BaseActivity_MembersInjector(supertypeInjector, applicationProvider); } }
一个类有@inject注解的时候就会生成这样的一个类,这类就是这个类所以需要注入的汇总。
@Generated("dagger.internal.codegen.ComponentProcessor") public final class DaggerActivityComponent implements ActivityComponent { private Provider<HRApp> getApplicationProvider; private MembersInjector<BaseActivity> baseActivityMembersInjector; private DaggerActivityComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } private void initialize(final Builder builder) { this.getApplicationProvider = new Factory<HRApp>() { private final AppComponent appComponent = builder.appComponent; @Override public HRApp get() { HRApp provided = appComponent.getApplication(); if (provided == null) { throw new NullPointerException("Cannot return null from a non-@Nullable component method"); } return provided; } }; this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), getApplicationProvider); } @Override public void inject(BaseActivity baseActivity) { baseActivityMembersInjector.injectMembers(baseActivity); } public static final class Builder { private ActivityModule activityModule; private AppComponent appComponent; private Builder() { } public ActivityComponent build() { if (activityModule == null) { this.activityModule = new ActivityModule(); } if (appComponent == null) { throw new IllegalStateException("appComponent must be set"); } return new DaggerActivityComponent(this); } public Builder activityModule(ActivityModule activityModule) { if (activityModule == null) { throw new NullPointerException("activityModule"); } this.activityModule = activityModule; return this; } public Builder appComponent(AppComponent appComponent) { if (appComponent == null) { throw new NullPointerException("appComponent"); } this.appComponent = appComponent; return this; } } }
看到了吧!我们经常写的void inject(xxx),这时候就会在对应的component里面生成对应的注入对象,这样component就知道谁需要注入了。
形象的说,含有注解的类生成的类相对于一次汇总将本类所有需求汇总汇报给component生成的类,然后comonent知道需要后就找生产对应对象的工厂要东西了。
调用api
dagger的调用api就是component生成的那个类,一般是先build出,然后调个inject(xxx),如果上面认真看代码的话,就可以看到这个方法将会调那个含注解类生成的类的方法,这个方法就真正实现了注入,而那个对象的提供者,是在component构建含注解类生成的类的时候传入的。好了,dagger流程基本就是这样,有个关键点没讲,那就是那个源码中是如何生成代码,没办法google没有开源dagger2的源码,我只能找到其中core部分的,其中编译部分找不到,有知道的人欢迎联系我。
后记
个人认为dagger的出现非常大解决了android耦合问题,和mvp配合简直耦合直降,代码结构瞬间清晰。希望大家以后多多使用mvp+dagger的组合写出优秀的代码相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories