Dagger依賴注入入門
來自: https://segmentfault.com/a/1190000004537518
依賴注入
目的:將類之間的依賴關系交由第三方管理spring IOC就是很有名的依賴注入框架,但是這個框架基于反射來實現,對性能要求比較高,所以不適合android平臺。dagger基于預編譯的方式完成依賴注入。
Dagger使用步驟
在使用Dagger前,首先要導入相關的包,如果使用Maven進行項目構建,則添加如下依賴即可:
<dependency>
<groupId>com.squareup.dagger</groupId>
<artifactId>dagger</artifactId>
<version>1.2.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.squareup.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>1.2.2</version>
</dependency></pre>
注意這里第二個依賴dagger-compiler很重要,一開始沒有加入這個依賴的時候,一直在報如下錯誤:
Module adapter for class XXXXX could not be loaded.Please ensure that code generation was run for this module.
原因是,dagger的依賴注入是通過預編譯而非反射來完成的(但是dagger還有些地方用到了反射【具體是哪里還有待研究】,dagger2完全脫離了反射)。dagger-compiler庫中的函數完成編譯工程,在編譯的過程中創建注入依賴所需要的類。
Dagger中基本的三個注解:@Inject,@Provides,@Moudle,最最簡單的情況需要使用@Inject,@Moudle。
示例場景:進影院看電影,首先要入座Seat,然后開始看電影watchMovie入座---->Seat類
public class Seat {
@Inject
public Seat() {
System.out.println("*********prepare to seat************");
}
public void seat(){
System.out.println("<----------- seating ---------->");
}
}</pre>
看電影--->WatchMovie類
public class WatchMovie {
@Inject Seat seat;
public void watchMovie(){
seat.seat();
System.out.println("<----------- watching ---------->");
}
}</pre>
Module類(這個類的作用待會兒說,現在先照著做就好啦!)
@Module(
injects = MovieTest.class,
library = true
)
public class MovieModule {
}</pre>
測試類--->MovieTest
public class MovieTest {
@Inject WatchMovie watchMovie;
public void movie(){
watchMovie.watchMovie();
}
public static void main(String[] args) {
ObjectGraph objectGraph = ObjectGraph.create(new MovieModule());
MovieTest movieTest = objectGraph.get(MovieTest.class);
movieTest.movie();
}
}</pre>
運行結果:
*prepare to seat**
<----------- seating ---------->
<----------- watching ---------->
Process finished with exit code 0</pre>
Dagger使用簡介
在dagger中,依賴注入的完成是通過只使用注解的方式表明在編譯時需要創建的類,使得你在類中用到的對象的引用不需要顯示地實例化。告訴dagger的編譯器需要在編譯時創建類的方式有如下三種:
-
使用@Inject注解構造函數
-
使用@Inject注解類的屬性
-
在@Module注解的類中提供構造對象的方法
在第一種方法中,如果@Inject注解的構造函數有參數,則這些參數所對應的類必須要么包含@Inject注解(可以是注解構造函數,也可以是注解類的屬性),要么在@Moudle注解的類中@Provides了這個類。第二種方法中注解的類的屬性也要滿足這個條件。
那么,什么情況下使用@Module吶?Dagger官方文檔中說,@Inject不能在以下三種情況下使用:
接口類型不能被構造,第三方的類不能被注釋構造,可配置的對象必須被配置好
以第一種情況為例,在剛才的場景中增加一個步驟:離開,接口為ILeave:
public interface ILeave {
void leave();
}
接口的實現LeaveImpl:
public class LeaveImpl implements ILeave {
@Override
public void leave() {
System.out.println("<----------- leaving ---------->");
}
}</pre>
WatchMovie修改為如下:
public class WatchMovie {
@Inject Seat seat;
@Inject ILeave leave;
public void watchMovie(){
seat.seat();
System.out.println("<----------- watching ---------->");
leave.leave();
}
}</pre>
這里增加了接口類型ILeave的注入,此時是不能用@Inject注解接口的,因為無法創建一個接口;并且被注解的屬性是ILeave類型,所以也不能去注解該接口的實現。此時就需要在@Module注解的類中,使用@Provides說明,當需要ILeave類型的對象時應當如何創建。故,在MovieModule中增加如下代碼:
@Provides
public ILeave provideLeave(){
return new LeaveImpl();
}
所有的@Provides只能出現在@Module所注解的類中,通過這種方式告訴程序,如果你需要ILeave類型的引用,就按照@Provides標注的方法中返回類型是ILeave的那個方法所提供的方式來獲取。
完整的@Module代碼:
@Module(
injects = MovieTest.class,
library = true
)
public class MovieModule {
@Provides
public ILeave provideLeave(){
return new LeaveImpl();
}
}</pre>
<p>@Module的injects參數表明,MovieTest.class這個類需要通過MovieModule來完成依賴注入。</p>
dagger依賴注入的最后一個步驟就是使用對象圖ObjectGraph。本示例使用對象圖的部分為:
ObjectGraph objectGraph = ObjectGraph.create(new MovieModule());
MovieTest movieTest = objectGraph.get(MovieTest.class);
ObjectGraph.create(new MovieModule())告訴編譯器,MovieTest類中用到的依賴關系根據MovieModule生成,接下來就可以通過objectGraph.get(MovieTest.class)生成完成了依賴注入的MovieTest類啦。
Dagger的作用
-
控制反轉本身的優點:可以解耦
-
方便測試
-
復用
You don't need a bunch of boilerplate just to swap the RpcCreditCardService out for a FakeCreditCardService.You can share the same AuthenticationModule across all of your apps. And you can run DevLoggingModule during development and ProdLoggingModule in production to get the right behavior in each situation.