Dagger is a fully static, compile-time dependency injection framework
https://medium.com/square-corner-blog/keeping-the-daggers-sharp-%EF%B8%8F-230b3191c3f
Favor constructor injection over field injection
Field injection requires the fields to be non final and non private.
Forgetting an @Inject on a field introduces a NullPointerException.
Constructor injection is better because it allows for immutable and therefore thread safe objects that don’t have a partially constructed state.
https://github.com/google/dagger
http://blog.zhaiyifan.cn/2016/03/27/android-new-project-from-0-p4/
https://medium.com/square-corner-blog/keeping-the-daggers-sharp-%EF%B8%8F-230b3191c3f
Favor constructor injection over field injection
Field injection requires the fields to be non final and non private.
Forgetting an @Inject on a field introduces a NullPointerException.
Constructor injection is better because it allows for immutable and therefore thread safe objects that don’t have a partially constructed state.
@Inject public CardConverter(PublicKeyManager publicKeyManager) {
this.publicKeyManager = publicKeyManager;
}
https://github.com/google/dagger
http://blog.zhaiyifan.cn/2016/03/27/android-new-project-from-0-p4/
关于Dagger2的最初想法,来自于2013年12月的Proposal: Dagger 2.0,Jake大神在issue里面也有回复哦,而idea的来源者Gregory Kick的GitHub个人主页也没多少follower,自己也没几个项目,主要都在贡献其他的repository,可见海外重复造轮子的风气比我们这儿好多了。
扯远了,Dagger2的诞生就是源于开发者们对Dagger1半静态化半运行时的不满(尤其是在服务端的大型应用上),想要改造成完整的静态依赖图生成,完全的代码生成式依赖注入解决方案。在权衡了什么对Android更适合,以及对大型应用来说什么更有意义(往往有可怕数量的注入)两者后,Dagger2诞生了。
是通过依赖注入让你少些很多公式化代码,更容易测试,降低耦合,创建可复用可互换的模块。你可以在Debug包,测试运行包以及release包优雅注入三种不同的实现。
但问题在于,在大型应用中,把这些依赖全都分离,然后自己去创建的话,会是一个很大的工作量——毫无营养的公式化代码,一堆Factory类。不仅仅是工作量的问题,这些依赖可能还有顺序的问题,A依赖B,B依赖C,B依赖D,如此一来C、D就必须在A、B的后面,手动去做这些工作简直是一个噩梦 =。=(哈哈,是不是想到了appliation初始化那些依赖)。Google的工程师碰到的问题就是在Android上有3000行这样的代码,而在服务器上的大型程序则是100000行。
Guice虽然较Spring进了一步,干掉了xml,通过Java声明依赖注入比起Spring好找多了,但其跟踪和报错(运行时的图验证)实在令人抓狂,而且在不同环境注入不同实例的配置也挺恶心的(if else各种判断),感兴趣的可以去看看,项目就在GitHub上,Android版本的叫RoboGuice。
而Dagger2和Dagger1的差别在上节已经提到了,更专注于开发者的体验,从半静态变为完全静态,从Map式的API变成申明式API(@Module),生成的代码更优雅,更高的性能(跟手写一样),更简单的debug跟踪,所有的报错也都是在编译时发生的。
@Component(modules = DripCoffeModule.class)
interface CoffeeMakerComponet {
CoffeeMaker getCoffeeMaker();
}
// 会生成这样的代码,Dagger_CoffeeMakerComponent里面就是一堆Provider,
// 或者是单例,或者是通过DripCoffeeModule申明new的方式,开发者不必关心依赖顺序
CoffeeMakerComponent component = Dagger_CoffeeMakerComponent.create();
CoffeeMaker coffeeMaker = component.getCoffeeMaker();
interface CoffeeMakerComponet {
CoffeeMaker getCoffeeMaker();
}
// 会生成这样的代码,Dagger_CoffeeMakerComponent里面就是一堆Provider,
// 或者是单例,或者是通过DripCoffeeModule申明new的方式,开发者不必关心依赖顺序
CoffeeMakerComponent component = Dagger_CoffeeMakerComponent.create();
CoffeeMaker coffeeMaker = component.getCoffeeMaker();
Dagger2的Scope,除了Singleton(root),其他都是自定义的,无论你给它命名PerActivity、PerFragment,其实都只是一个命名而已,真正起作用的是inject的位置,以及dependency。
Scope起的更多是一个限制作用,比如不同层级的Component需要有不同的scope,注入PerActivity scope的component后activity就不能通过@Inject去获得SingleTon的实例,需要从application去暴露接口获得(getAppliationComponent获得component实例然后访问,比如全局的navigator)。
当然,另一方面则是可读性和方便理解,通过scope的不同很容易能辨明2个实例的作用域的区别。