Dagger2 简明教程 [TOC]
第一章:依赖注入与控制反转 面向对象编程需要处理各种依赖关系,多个对象或者组件互相依赖。通常,我们都会自己通过new来创建依赖对象。但是,这样通常会带来一系列的问题。
对象和它的依赖项形成强依赖,如果我们要替换依赖项的实现,那我们就不得不去修改对象。
在对对象进行测试时,我们不得不先创建它的依赖项,如果对象依赖项很多,那么将非常痛苦。
依赖注入与控制反转是一种思想。在这个世界里,对象的依赖不是有自己提供,而是由外部容器提供,容器由所有它需要的依赖,容器找到它的依赖,并将它们注入给对象。
控制反式IOC : 控制反转是将组件间的依赖关系从程序内部提到外部由容器来管理。
依赖注入D : 依赖注入是指将组件的依赖通过外部以参数或其他形式由容器注入,并非有组件自己提供。通常依赖注入有两种方式:设值注入和构造注入。设值注入指通过set的方法传入,构造注入指通过构造函数的方式传入参数。
第二章:JDK中的依赖注入 JDK本身提供了依赖注入的框架,但是JDK没有提供实现。我们先看下JDK中的框架。
第三章:Dagger2
在下面的内容中,我们称需要注入的对象称为对象。那些注入的对象我们称为依赖。 我们称A为对象,B为依赖。
Dagger2是依赖注入与控制反转思想的一种Java实现。除Dagger2外,java中最重量的该框架就是Spring。 Spring是JavaWeb开发最火最优秀的框架。
思考一下: 如果抛却这些框架,自己实现这样一个框架。那么框架需要做哪些最基本的事?
框架需要知道对象需要哪些依赖。
框架需要知道如何生成这些依赖。
框架需要知道如何把依赖注入给对象。
有了这些,我们就可以有一个基本的框架实现。
在额外思考一下,多个对象都依赖一个依赖项,框架在生成依赖时,:
如何做到依赖是单例。
如何区分出不用的依赖。
那我们来领略一下Dagger2是怎么做的吧。
Dagger2 简介 Dagger是一个完全静态的,Java和Android的编译时依赖注入框架。它改编了由Square 创建的早期版本,现在由Google维护。
Dagger2 简明使用
引入依赖
1 2 3 4 5 6 7 8 9 10 //纯java依赖 compile 'com.google.dagger:dagger:2.16' annotationProcessor 'com.google.dagger:dagger-compiler:2.16' //下面的可不添加 //Android依赖库-非必须项 compile 'com.google.dagger:dagger-android:2.16' annotationProcessor 'com.google.dagger:dagger-android-processor:2.16' //Android support依赖库-非必须项 compile 'com.google.dagger:dagger-android-support:2.16'
基本使用
Daggaer2 剖析 按照我们提出的问题,我们一步一步梳理Dagger2是如何解决这些问题的。
问题1 -》框架如何知道对象需要哪些依赖。 1 2 3 4 5 6 7 8 9 10 11 12 public class MainActivity extends AppCompatActivity { @Inject Boss boss; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
问题2 -》框架需要知道如何生成这些依赖。
使用@Inject注解在类的构造函数上
对于我们自己写的类, 我们可以直接类的构造函数上添加@Inject 来表示提供依赖。
1 2 3 4 5 6 7 public class Boss { @Inject public Boss() { } }
使用@module注解
对于第三发类等我们不能修改的类或者其它不能添加@Inject的类, 我们可以使用模块来表示提供依赖. Dagger2使用@Module和@Provides来提供依赖。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Module public class ActivityModule { @Provides public ExecutorService provideExecutorService() { return Executors.newSingleThreadExecutor(); } @Provides public ThreadFactory provideThreadFactory() { return Executors.defaultThreadFactory(); } }
问题3 -》框架需要知道如何把依赖注入给对象 Dagger2 通过编著Component注解的类完成注入工作。形式如下
1 2 3 @Component() public interface ActivityComponent { }
build一下工程,将会为我们生成如下的类。
生成的类
提供依赖的类,Dagger2为每一个提供依赖的类生成一个工厂类来生成依赖。 他们的继承广西是这样的
1 2 3 graph BT CLASS_Factory-->Factory Factory-->Provider
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public final class Boss_Factory implements Factory<Boss> { private static final Boss_Factory INSTANCE = new Boss_Factory(); @Override public Boss get() { return provideInstance(); } public static Boss provideInstance() { return new Boss(); } public static Boss_Factory create() { return INSTANCE; } public static Boss newBoss() { return new Boss(); } }
使用module注解的类,生成的类名为 模块名+方法名字+Factory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 public final class ActivityModule_ProvideExecutorServiceFactory implements Factory<ExecutorService> { private final ActivityModule module; public ActivityModule_ProvideExecutorServiceFactory(ActivityModule module) { this.module = module; } @Override public ExecutorService get() { return provideInstance(module); } public static ExecutorService provideInstance(ActivityModule module) { return proxyProvideExecutorService(module); } public static ActivityModule_ProvideExecutorServiceFactory create(ActivityModule module) { return new ActivityModule_ProvideExecutorServiceFactory(module); } public static ExecutorService proxyProvideExecutorService(ActivityModule instance) { return Preconditions.checkNotNull( instance.provideExecutorService(), "Cannot return null from a non-@Nullable @Provides method"); } } public final class ActivityModule_ProvideThreadFactoryFactory implements Factory<ThreadFactory> { private final ActivityModule module; public ActivityModule_ProvideThreadFactoryFactory(ActivityModule module) { this.module = module; } @Override public ThreadFactory get() { return provideInstance(module); } public static ThreadFactory provideInstance(ActivityModule module) { return proxyProvideThreadFactory(module); } public static ActivityModule_ProvideThreadFactoryFactory create(ActivityModule module) { return new ActivityModule_ProvideThreadFactoryFactory(module); } public static ThreadFactory proxyProvideThreadFactory(ActivityModule instance) { return Preconditions.checkNotNull( instance.provideThreadFactory(), "Cannot return null from a non-@Nullable @Provides method"); } }
需要注入的类,Dagger2为每一个需要注入的类生成一个实现MembersInjector的类,来完成注入工作。
1 2 graph BT CLASS_MembersInjector-->MembersInjector
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> { private final Provider<Boss> bossProvider; public MainActivity_MembersInjector(Provider<Boss> bossProvider) { this.bossProvider = bossProvider; } public static MembersInjector<MainActivity> create(Provider<Boss> bossProvider) { return new MainActivity_MembersInjector(bossProvider); } @Override public void injectMembers(MainActivity instance) { injectBoss(instance, bossProvider.get()); } public static void injectBoss(MainActivity instance, Boss boss) { instance.boss = boss; } }
在生成的类中,Dagger会为每个需要注入的成员,
添加一个Provider类型的成员。
构造函数和静态工厂方法添加一个对应的Provider类型的参数。
添加inject*的方法,并在injectMembers调用。
关联起来二者的component Dagger2会生成对应的类实现或者继承我们的Component注解的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public final class DaggerActivityComponent implements ActivityComponent { private DaggerActivityComponent(Builder builder) {} public static Builder builder() { return new Builder(); } public static ActivityComponent create() { return new Builder().build(); } public static final class Builder { private Builder() {} public ActivityComponent build() { return new DaggerActivityComponent(this); } } }
可以看到,我们的类使用了静态的工厂方法和Builder方法的设计模式。
到现在为止,我们只是看到了基本的实现。而且component类里有没有真的注入。接下来,我们修改Componet来完成注入。
1 2 3 4 5 @Component() public interface ActivityComponent { void inject(MainActivity mainActivity); }
Build工程后,可以看到生成的类增加了下面两个方法。实际上,Dagger2会每一个需要注入的成员 增加这样两个方法。
1 2 3 4 5 6 void inject(MainActivity mainActivity) 和 private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectBoss(instance, new Boss()); return instance; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public final class DaggerActivityComponent implements ActivityComponent { private DaggerActivityComponent(Builder builder) {} public static Builder builder() { return new Builder(); } public static ActivityComponent create() { return new Builder().build(); } public static final class Builder { private Builder() {} public ActivityComponent build() { return new DaggerActivityComponent(this); } } } //变更后 public final class DaggerActivityComponent implements ActivityComponent { private DaggerActivityComponent(Builder builder) {} public static Builder builder() { return new Builder(); } public static ActivityComponent create() { return new Builder().build(); } @Override public void inject(MainActivity mainActivity) { injectMainActivity(mainActivity); } private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectBoss(instance, new Boss()); return instance; } public static final class Builder { private Builder() {} public ActivityComponent build() { return new DaggerActivityComponent(this); } } }
到此,好像所有的类都有了,但少了一点,为MainActivity注入的方法,好像没人调用。我们增加最后一步,来完成所有的工作。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class MainActivity extends AppCompatActivity { @Inject Boss boss; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DaggerActivityComponent.create().inject(this); System.out.println(boss); } }
运行代码我们就可以看到boss,已经被设置了值了。
1 06-21 11:45:31.189 1710-1710/davy.dagger2learn I/System.out: davy.dagger2learn.Boss@8c15cb2
来看下,那些基类的代码
1 2 3 4 5 6 7 8 9 10 import javax.inject.Provider; public interface Factory<T> extends Provider<T> { } public interface MembersInjector<T> { void injectMembers(T instance); }
上面说到了使用@Inject提供注解来提供依赖的类BOSS。 但是使用@Module注解的类 并没有说到。下面说这个问题。
首先,修改MainActivity,添加
1 2 @Inject ThreadFactory threadFactory;
接下来,build工程,发现报错了信息如下:
1 2 3 4 5 错误: [Dagger/MissingBinding] java.util.concurrent.ThreadFactory cannot be provided without an @Provides-annotated method. java.util.concurrent.ThreadFactory is injected at davy.dagger2learn.MainActivity.threadFactory davy.dagger2learn.MainActivity is injected at davy.dagger2learn.ActivityComponent.inject(davy.dagger2learn.MainActivity)
意思是:使用@Provides注解的方法提供的类, 无法提供依赖。
正确的方式是。使用Provides提供依赖 需要在Compoent中将Module添加进来。
修改如下:
1 2 3 4 @Component(modules = {ActivityModule.class}) public interface ActivityComponent { void inject(MainActivity mainActivity); }
再次运行,发现功能正常了。
查看生产的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 public final class DaggerActivityComponent implements ActivityComponent { private ActivityModule activityModule; private DaggerActivityComponent(Builder builder) { initialize(builder); } public static Builder builder() { return new Builder(); } public static ActivityComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.activityModule = builder.activityModule; } @Override public void inject(MainActivity mainActivity) { injectMainActivity(mainActivity); } private MainActivity injectMainActivity(MainActivity instance) { MainActivity_MembersInjector.injectBoss(instance, new Boss()); MainActivity_MembersInjector.injectThreadFactory( instance, ActivityModule_ProvideThreadFactoryFactory.proxyProvideThreadFactory(activityModule)); return instance; } public static final class Builder { private ActivityModule activityModule; private Builder() {} public ActivityComponent build() { if (activityModule == null) { this.activityModule = new ActivityModule(); } return new DaggerActivityComponent(this); } public Builder activityModule(ActivityModule activityModule) { this.activityModule = Preconditions.checkNotNull(activityModule); return this; } } }
我们发现,
对于使用@Inject在构造函数的类,Dagger2直接使用new 创建类。
对于使用Module的类,是在DaggerActivityComponent添加module 成员来提供依赖。
第四章:总结 上面,我们总结并学会了Dagger2的基本用法。
使用@Inject在成员上,标识需要注入
使用@Inject在构造函数上,标识可以提供依赖。
使用@Module和@Provides标注类和方法,标识提供依赖。
使用@Component标注类,并添加inject方法,来将上面提供的依赖和需要注入的类结合起来,
使用Daggee*Component来完成注入工作。