Dagger2 —— 匪夷所思,结果那么爱你

简介:

开天辟地

今天我们来讲讲一个有一点点冷门的库Dagger吧。我做一个不负责任的猜测:做客户端的同学可能比较少听到一些名词,比如面向切面编程、控制反转、依赖注入,相信玩过Spring的同学肯定知道这些一开始让人头大后来却很好玩的玩意儿。

今天我们来介绍这款依赖注入器 —— Dagger2,源自Square的Dagger,由Google开发,基于apt生成静态编译时的依赖注入工具,比动态注入的方式更加高性能,但是需要更多的约定。

官网:https://google.github.io/dagger/

组成

Dagger2(以下称为Dagger) 主要由两个部分组成:Component和Module。分别作为注入器和注入源存在于整个依赖图中,然后有了源和工具,那么只用在我们需要注入的地方加上@Inject注解即可,它是属于JSR-330的一部分,我们这里就直接引入一个最简单的Demo。

Module


  
  
  1. @Module 
  2. public class AppModule { 
  3.     Context mApplicationContext; 
  4.  
  5.     public AppModule(Context context) { 
  6.         this.mApplicationContext = context; 
  7.     } 
  8.  
  9.     @Provides 
  10.     public Context provideContext(){ 
  11.         return mApplicationContext; 
  12.     } 
  13.  
  14.     @Provides 
  15.     public Service provideService(Context context) { 
  16.         return new Service(context, null); 
  17.     } 

这是世界的起源。

  • @Module注解表示这个类是个Module,是一个“源”。
  • @Provides注解告诉Dagger我们想要构造对象并提供这些依赖。

Component


  
  
  1. @Component(modules=AppModule.class) 
  2. public interface AppComponent { 
  3.     void inject(App app); 
  4.  
  5.     Context context(); 
  6.     Service service(); 

Component是一个接口,具体的实现由Dagger经过apt工具为你生成(是不是有了apt就特别爽),我们给AppComponent这枚“针”指定了药剂——AppModule,告诉它注入的时候,从AppModule里面拿到我们要的变量实例,只要给Component声明一个无返回值,带被注入类型形参的方法,Dagger 就会为这个类生成一个MemberInjector对象,用来给被注入类注入对象。

被注入对象


  
  
  1. public class App extends Application { 
  2.  
  3.     @Inject Service mService; 
  4.      
  5.     private AppComponent mAppComponent; 
  6.  
  7.     /** 
  8.      * 应用程序初始化 
  9.      */ 
  10.     @Override 
  11.     public void onCreate() { 
  12.         super.onCreate(); 
  13.         mAppComponent = DaggerAppComponent.builder() 
  14.                 .appModule(new AppModule(this)) 
  15.                 .build(); 
  16.  
  17.         mAppComponent.inject(this); 
  18.  
  19.     } 
  20.      
  21.     public AppComponent getAppComponent() { 
  22.         return mAppComponent; 
  23.     } 

这里的DaggerAppComponent是Dagger生成的,它的实现类会在所有Component接口类之前增加一个Dagger前缀,我们只用传入它所需要的依赖即可,Component显然是依赖Module的,所以需要在这里传入AppModule,现在,只要用Context的地方,我们都可以拿到这个AppComponent实例,只要有这个实例,我们可以在任意地方注入被管理的类。

作用域

我们说依赖注入的时候,作用域(Scope)是经常会出现在我们眼里的词汇。控制变量生命周期,实质就是控制它存在的作用域,服务端典型的作用域如单例(Singleton),Request,Session,等等,它们的变量分别存在于不同的生命周期。

我们默认存在的是Singleton,也就是@Singleton注解。由它标注的Provider生成的对象会被缓存起来,用SingleCheck或者DoubleCheck进行包装。我们Provider指定的作用域需要和Component的作用域一致。

比如Component这样定义:


  
  
  1. @Singleton 
  2. @Component(modules=AppModule.class) 
  3. public interface AppComponent { 
  4.     void inject(App app); 
  5.  
  6.     Service service(); 

而Module就是这个样子


  
  
  1. @Module 
  2. public class AppModule { 
  3.     Context mApplicationContext; 
  4.  
  5.     public AppModule(Context context) { 
  6.         this.mApplicationContext = context; 
  7.     } 
  8.  
  9.     @Singleton 
  10.     @Provides 
  11.     public Context provideService(){ 
  12.         return new Service(); 
  13.     } 
  14.  

限定符

Dagger还支持使用限定符(Qualifier)来指定注入的对象,比如内置的@Named限定符,我们在需要特定限定名字的变量的时候,可以在@Inject上,指定@Named限定符,获取指定对象。


  
  
  1. //Module 
  2. @Providers 
  3. @Named("cache"
  4. public Service provideService(); 
  5.  
  6. // Injection 
  7. @Inject 
  8. @Named("cache"
  9. Service mService; 

这样就给这个mService注入了名字为"cache"的实例了。

一个简单场景的应用

当我们谈论依赖注入的时候,我们在谈论什么?

其实我们是在讨论 作用域。

这是什么意思呢,我相信每一个程序员去实现一个单例是一件非常简单的事情,makeInstance和getInstance嘛。但是,你们想过维护“双例”吗?我之前碰到了一个场景如下:

  1. 用户(User) 需要一张tag表,会增删查改,并和用户相关联。
  2. 问题(Question) 也需要一张tag表,也会增删查改,和问题关联。
  3. 这两张表的实体模型一模一样。

那么我们采取的方案有两种,双表,或者双库。双表的话,对ORM很不友好,因为ORM是根据类来确定表的,我们为了代码简洁优雅,不可能创建两个一模一样的类,不然取名都变成一件困难的事。这里,一个优势是,我使用的ORM库首先是维护一个单例,单例进行CRUD操作,且一个单例和一个数据库相关。于是我使用Qualifer的特性,生成了两个实例(也就是对应了两个数据库),分别注入到不同的业务模型中去,他们就可以使用同一个类,而且对tag的修改完全没有影响。这件事要是我们自己去做的话,可能要写很多肮脏不堪的代码,但是Dagger只用2个注解就把我的需求解决了。

总结

好了,本文简单的阐述了Dagger入门使用,总结起来,我们只要约定好Componenet、Module,搭配Inject使用,即可实现一个静态的依赖注入流程。下一次我们详细介绍Dagger生成的代码结构。




作者:Gemini
来源:51CTO
目录
相关文章
|
6月前
|
容器
Dagger2的使用
Dagger2的使用
44 0
|
机器学习/深度学习
1250:The Castle 2021-01-05
1250:The Castle 2021-01-05
|
Android开发
Dagger Hilt - ViewModel的依赖注入及实现原理
Dagger Hilt VIewModel 依赖注入的原理
487 0
|
缓存 Android开发 开发者
Dagger2 框架与 SystemUI
Dagger2 框架与 SystemUI
Dagger2 框架与 SystemUI
|
缓存 Android开发 开发者
Dagger2和它在SystemUI上的应用
Dagger2和它在SystemUI上的应用
Dagger2和它在SystemUI上的应用
|
存储 前端开发 Java
Jetpack 系列(10)—— 从 Dagger2 到 Hilt 玩转依赖注入(一)
Jetpack 系列(10)—— 从 Dagger2 到 Hilt 玩转依赖注入(一)
442 0
Jetpack 系列(10)—— 从 Dagger2 到 Hilt 玩转依赖注入(一)
Android | 依赖注入与 Dagger2 框架【@Deprecated】
Android | 依赖注入与 Dagger2 框架【@Deprecated】
209 0
Android | 依赖注入与 Dagger2 框架【@Deprecated】
CoreLocation第三方框架
CoreLocation第三方框架
119 0
CoreLocation第三方框架
|
存储 设计模式 前端开发
依赖注入之Dagger2初探
依赖注入之Dagger2初探
234 0
|
Java Maven Android开发
Dagger2 入门解析
前言 在为dropwizard选择DI框架的时候考虑了很久。Guice比较成熟,Dagger2主要用于Android。虽然都是google维护的,但Dagger2远比guice更新的频率高。再一个是,Dagger2不同于guice的运行时注入,编译时生成代码的做法很好。
2018 0