1 Dagger2簡(jiǎn)介
Dagger2提供給Java和Android使用,主要用于模塊間解耦、提高代碼的健壯性和可維護(hù)性。它是一款依賴注入框架,使用了IOC(控制反轉(zhuǎn))的思想,在編譯階段使用APT利用Java注解生成Java代碼,然后結(jié)合部分手寫代碼來(lái)完整依賴注入工作。
運(yùn)行前需要先編譯一次項(xiàng)目,目的是用APT生成中間代碼。Dagger2不使用反射,在編譯階段生成代碼,所以不會(huì)程序性能有影響。
IOC(控制反轉(zhuǎn))和依賴注入的區(qū)別:
控制反轉(zhuǎn)是一種在軟件工程中解耦合的思想,調(diào)用類只依賴接口,而不依賴具體的實(shí)現(xiàn)類,減少了耦合。 控制權(quán)交給了容器,在運(yùn)行的時(shí)候才由容器決定將具體的實(shí)現(xiàn)動(dòng)態(tài)的“注入”到調(diào)用類的對(duì)象中。 依賴注入是一種設(shè)計(jì)模式,可以作為控制反轉(zhuǎn)的一種實(shí)現(xiàn)方式。
Dagger2官網(wǎng):https://dagger.dev/
Dagger2 Github:https://github.com/google/dagger
2 Dagger2原理解析

可以使用用戶在網(wǎng)上買東西,然后通過(guò)快遞配送來(lái)理解Dagger2的使用原理。用戶購(gòu)買一本書(@Inject注解),然后賣家(Module)進(jìn)行打包,接著快遞員(Component)配送,然后用戶就收到了這本書。這樣就達(dá)到了解耦的目的,只需要使用@Inject注解,就能獲取到該對(duì)象。
3 Dagger2中的注解
Dagger2通過(guò)注解使用APT生成代碼,所以首先要知道Dagger2中常用注解的使用。
3.1 @Inject
@Inject有兩種用處,一是用來(lái)標(biāo)注需要依賴獲取的對(duì)象,比如:
public class FirstActivity extends AppCompatActivity {
@Inject
Book book;
...
}
就表示在當(dāng)前類中,需要依賴Book。
二是用來(lái)標(biāo)注構(gòu)造方法,Dagger2通過(guò)@Inject注解可以在需要這個(gè)類實(shí)例的時(shí)候來(lái)找到這個(gè)構(gòu)造函數(shù)并把相關(guān)實(shí)例構(gòu)造出來(lái),以此來(lái)為被@Inject標(biāo)記了的變量提供依賴,同時(shí)會(huì)在build下生成對(duì)應(yīng)的xxx_Factory類,后面示例中會(huì)詳解。
public class Book {
@Inject
public Book() {
}
}
3.2 @Module
@Module用來(lái)標(biāo)注提供依賴對(duì)象的類,也就是“包裹”Module類,Module類中會(huì)有一個(gè)方法來(lái)提供依賴對(duì)象,在這個(gè)方法中可以對(duì)注入對(duì)象的有參構(gòu)造函數(shù)傳入?yún)?shù)或者進(jìn)行其他處理。
3.3 @Provides
@Provides用來(lái)標(biāo)注Module類中的提供依賴對(duì)象的方法進(jìn)行標(biāo)注,該方法在需要提供依賴時(shí)被調(diào)用,從而把預(yù)先提供好的對(duì)象當(dāng)做依賴給標(biāo)注了@Inject 的變量賦值。
被@Module和@Provides標(biāo)注的類在build下會(huì)生成對(duì)應(yīng)的xxxModule_xxxFactory類。
3.4 @Component
@Component用來(lái)標(biāo)注接口,該接口提供了方法用來(lái)傳入業(yè)務(wù)層,是業(yè)務(wù)層和Module之間的連接器。標(biāo)注后會(huì)在build下生成DaggerxxxComponent類。
3.5 @Singleton
默認(rèn)情況下,@Inject獲取到的依賴對(duì)象是非單例的,要想實(shí)現(xiàn)單例,需要用@Singleton對(duì)Module中的provide方法和Conponent接口進(jìn)行標(biāo)注。
4 Dagger2使用
引入依賴:
implementation 'com.google.dagger:dagger:2.41'
annotationProcessor 'com.google.dagger:dagger-compiler:2.41'
4.1 獲取到的依賴注入對(duì)象是非單例
創(chuàng)建商品Book。
public class Book {
@Inject
public Book() {
}
}
創(chuàng)建包裹Module。
@Module
public class BookModule {
@Provides
public Book provideBook() {
return new Book();
}
}
創(chuàng)建快遞員Component。
@Component(modules = BookModule.class)
public interface BookComponent {
void injectFirstActivity(FirstActivity activity);
void injectSecondActivity(SecondActivity activity);
}
創(chuàng)建兩個(gè)FirstActivity,通過(guò)@Inject獲取兩個(gè)依賴注入對(duì)象Book,并打印兩個(gè)Book的hasCode。
public class FirstActivity extends AppCompatActivity {
private static final String TAG = "zhangmushui";
@Inject
Book book;
@Inject
Book book2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
//DaggerBookComponent是由dagger-compiler通過(guò)APT自動(dòng)生成的
DaggerBookComponent.builder()
.bookModule(new BookModule())
.build().injectFirstActivity(this);
//另個(gè)Book的hashCode不一樣,說(shuō)明Dagger2提供的Book默認(rèn)是非單例的
Log.d(TAG, "book: " + book.hashCode());
Log.d(TAG, "book2: " + book2.hashCode());
findViewById(R.id.button).setOnClickListener(v ->
startActivity(new Intent(this, SecondActivity.class)));
}
}
創(chuàng)建SecondActivity
public class SecondActivity extends AppCompatActivity {
private static final String TAG = "zhangmushui";
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
DaggerBookComponent.builder()
.bookModule(new BookModule())
.build().injectSecondActivity(this);
Log.d(TAG, "book: " + book.hashCode());
}
}
控制臺(tái)可以看到,兩個(gè)頁(yè)面中的3個(gè)Book對(duì)象的hasCode都不同,可見通過(guò)Dagger2默認(rèn)獲取到的依賴注入對(duì)象是非單例的。
2022-04-20 17:00:04.388 6649-6649/cn.zhangmushui.dagger D/zhangmushui: book2: 94427313
2022-04-20 17:00:16.220 6649-6649/cn.zhangmushui.dagger D/zhangmushui: book: 63721347
2022-04-20 18:46:50.724 6649-6649/cn.zhangmushui.dagger D/zhangmushui: book: 194950979
4.2 獲取到的依賴注入對(duì)象是局部單例
首先在Module的provide方法上加上@Singleton,需要注意一點(diǎn)的是,之前版本的Dagger2需要在Module類上也添加@Singleton注解,新版本的已經(jīng)不需要。
/**
* 想要提供的對(duì)象是單例,需要加上@Singleton注解
* 但是最新版本的Dagger2已經(jīng)不需要在Module上添加@Singleton注解(不然編譯會(huì)報(bào)錯(cuò)),只需要在下面的provider和Component上添加@Singleton即可。
*/
@Module
public class BookModule {
@Singleton
@Provides
public Book provideBook() {
return new Book();
}
}
然后在Component類上添加@Singleton注解。
@Singleton
@Component(modules = BookModule.class)
public interface BookComponent {
void injectFirstActivity(FirstActivity activity);
void injectSecondActivity(SecondActivity activity);
}
重新編譯后運(yùn)行,可以看到FirstActivity中的兩個(gè)Book的hashCode是相同的,SecondActivity和FirstActivity中的Book對(duì)象hashCode是不一樣的,可見實(shí)現(xiàn)了局部單例。
2022-04-20 19:11:04.306 9367-9367/cn.zhangmushui.dagger D/zhangmushui: book: 29400920
2022-04-20 19:11:04.306 9367-9367/cn.zhangmushui.dagger D/zhangmushui: book2: 29400920
2022-04-20 19:11:06.047 9367-9367/cn.zhangmushui.dagger D/zhangmushui: book: 146490930
4.3 獲取到的依賴注入對(duì)象是全局單例
在上邊的基礎(chǔ)上繼續(xù)做修改,創(chuàng)建Application,在Application中實(shí)例化Component對(duì)象,并提供獲取Component的方法。
public class MainApplication extends Application {
private BookComponent mBookComponent;
@Override
public void onCreate() {
super.onCreate();
mBookComponent = DaggerBookComponent.builder()
.bookModule(new BookModule())
.build();
}
public BookComponent getBookComponent() {
return mBookComponent;
}
}
然后在Activity中通過(guò)Application去獲取Component。
public class FirstActivity extends AppCompatActivity {
private static final String TAG = "zhangmushui";
@Inject
Book book;
@Inject
Book book2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
//在Application中獲取Component,實(shí)現(xiàn)全局單例
((MainApplication) getApplication()).getBookComponent().injectFirstActivity(this);
//兩個(gè)Book的。hashCode一致。
Log.d(TAG, "book: " + book.hashCode());
Log.d(TAG, "book2: " + book2.hashCode());
findViewById(R.id.button).setOnClickListener(v ->
startActivity(new Intent(this, SecondActivity.class)));
}
}
public class SecondActivity extends AppCompatActivity {
private static final String TAG = "zhangmushui";
@Inject
Book book;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
((MainApplication) getApplication()).getBookComponent().injectSecondActivity(this);
//SecondActivity和FirstActivity中的Book的hashCode一致。
Log.d(TAG, "book: " + book.hashCode());
}
}
編譯后運(yùn)行查看日志,發(fā)現(xiàn)兩個(gè)頁(yè)面的3個(gè)Book的hashCode都是一樣的,這就實(shí)現(xiàn)了全局單例。
2022-04-20 19:15:13.890 9544-9544/cn.zhangmushui.dagger D/zhangmushui: book: 29400920
2022-04-20 19:15:13.890 9544-9544/cn.zhangmushui.dagger D/zhangmushui: book2: 29400920
2022-04-20 19:15:23.048 9544-9544/cn.zhangmushui.dagger D/zhangmushui: book: 29400920
5 Dagger2原理解析
接下來(lái)以默認(rèn)非單例的版本去分析Dagger2的原理。
所有用注解標(biāo)注的類,Dagger2都會(huì)用APT在build下去生成對(duì)應(yīng)的輔助類,這些輔助類的名字是根據(jù)dagger-compiler注解依賴庫(kù)中的命名規(guī)則生成的。
| 手動(dòng)創(chuàng)建 | APT生成 | 命名規(guī)則 | 注解 |
|---|---|---|---|
| FirstActivity | FirstActivity_MembersInjector | 類名_MembersInjector | @Inject |
| SecondActivity | SecondActivity_MembersInjector | 類名_MembersInjector | @Inject |
| BookComponent | DaggerBookComponent | Dagger對(duì)象名Component | |
| @Component | |||
| BookModule | BookModule_ProvideBookFactory | 對(duì)象名Module_方法名Factory | @Module @Provides |
| Book | Book_Factory | 對(duì)象名_Factory | @Inject |
為了方便觀看,原理直接寫到注釋里邊,注釋前邊用數(shù)字標(biāo)出,表示大概的調(diào)用順序。
// Generated by Dagger (https://dagger.dev).
package cn.zhangmushui.dagger.demo1;
import cn.zhangmushui.dagger.demo1.activity.FirstActivity;
import cn.zhangmushui.dagger.demo1.activity.FirstActivity_MembersInjector;
import cn.zhangmushui.dagger.demo1.activity.SecondActivity;
import cn.zhangmushui.dagger.demo1.activity.SecondActivity_MembersInjector;
import dagger.internal.DaggerGenerated;
import dagger.internal.Preconditions;
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class DaggerBookComponent implements BookComponent {
private final BookModule bookModule;
private final DaggerBookComponent bookComponent = this;
private DaggerBookComponent(BookModule bookModuleParam) {
this.bookModule = bookModuleParam;
}
public static Builder builder() {
//1 使用構(gòu)造者模式實(shí)例化DaggerBookComponent對(duì)象
return new Builder();
}
public static BookComponent create() {
return new Builder().build();
}
@Override
public void injectFirstActivity(FirstActivity activity) {
injectFirstActivity2(activity);
}
@Override
public void injectSecondActivity(SecondActivity activity) {
injectSecondActivity2(activity);
}
private FirstActivity injectFirstActivity2(FirstActivity instance) {
//4 Activity中的@Inject生成injectBook方法,通過(guò)BookModule_ProvideBookFactory來(lái)獲取依賴注入對(duì)象
FirstActivity_MembersInjector.injectBook(instance, BookModule_ProvideBookFactory.provideBook(bookModule));
FirstActivity_MembersInjector.injectBook2(instance, BookModule_ProvideBookFactory.provideBook(bookModule));
return instance;
}
private SecondActivity injectSecondActivity2(SecondActivity instance) {
SecondActivity_MembersInjector.injectBook(instance, BookModule_ProvideBookFactory.provideBook(bookModule));
return instance;
}
public static final class Builder {
private BookModule bookModule;
private Builder() {
}
//2 傳入一個(gè)BookModule對(duì)象
public Builder bookModule(BookModule bookModule) {
this.bookModule = Preconditions.checkNotNull(bookModule);
return this;
}
//3 實(shí)例化DaggerBookComponent
public BookComponent build() {
if (bookModule == null) {
this.bookModule = new BookModule();
}
return new DaggerBookComponent(bookModule);
}
}
}
// Generated by Dagger (https://dagger.dev).
package cn.zhangmushui.dagger.demo1;
import dagger.internal.DaggerGenerated;
import dagger.internal.Factory;
import dagger.internal.Preconditions;
import dagger.internal.QualifierMetadata;
import dagger.internal.ScopeMetadata;
@ScopeMetadata
@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class BookModule_ProvideBookFactory implements Factory<Book> {
private final BookModule module;
public BookModule_ProvideBookFactory(BookModule module) {
this.module = module;
}
@Override
public Book get() {
return provideBook(module);
}
public static BookModule_ProvideBookFactory create(BookModule module) {
return new BookModule_ProvideBookFactory(module);
}
//5 通過(guò)BookModule拿到Book對(duì)象,并用Dagger2提供的Preconditions.checkNotNullFromProvides()方法來(lái)檢查獲取到的對(duì)象是否為空
public static Book provideBook(BookModule instance) {
return Preconditions.checkNotNullFromProvides(instance.provideBook());
}
}
// Generated by Dagger (https://dagger.dev).
package cn.zhangmushui.dagger.demo1.activity;
import cn.zhangmushui.dagger.demo1.Book;
import dagger.MembersInjector;
import dagger.internal.DaggerGenerated;
import dagger.internal.InjectedFieldSignature;
import dagger.internal.QualifierMetadata;
import javax.inject.Provider;
@QualifierMetadata
@DaggerGenerated
@SuppressWarnings({
"unchecked",
"rawtypes"
})
public final class FirstActivity_MembersInjector implements MembersInjector<FirstActivity> {
private final Provider<Book> bookProvider;
private final Provider<Book> book2Provider;
public FirstActivity_MembersInjector(Provider<Book> bookProvider, Provider<Book> book2Provider) {
this.bookProvider = bookProvider;
this.book2Provider = book2Provider;
}
public static MembersInjector<FirstActivity> create(Provider<Book> bookProvider,
Provider<Book> book2Provider) {
return new FirstActivity_MembersInjector(bookProvider, book2Provider);
}
@Override
public void injectMembers(FirstActivity instance) {
injectBook(instance, bookProvider.get());
injectBook2(instance, book2Provider.get());
}
@InjectedFieldSignature("cn.zhangmushui.dagger.demo1.activity.FirstActivity.book")
public static void injectBook(FirstActivity instance, Book book) {
//6 將獲取到的Book對(duì)象賦值給Activity中的book
instance.book = book;
}
@InjectedFieldSignature("cn.zhangmushui.dagger.demo1.activity.FirstActivity.book2")
public static void injectBook2(FirstActivity instance, Book book2) {
instance.book2 = book2;
}
}
以上幾處注釋,就是Dagger2的核心原理,也就是通過(guò)Dagger生成輔助類,在業(yè)務(wù)層需要獲取依賴對(duì)象的地方使用@Inject去標(biāo)注對(duì)象,就可以交給Dagger2的這些輔助類去實(shí)例化對(duì)象,起到了解耦的作用,提高了代碼的可讀性和可維護(hù)性。
類圖如下,白色的是手動(dòng)創(chuàng)建的類,灰色的是APT生成的類。

完整源碼下載:https://gitee.com/mushuicode/dagger
關(guān)注木水小站 (zhangmushui.cn)和微信公眾號(hào)【木水Code】,及時(shí)獲取更多最新文章。