目的:將類之間的依賴關係交由第三方管理
spring IOC就是頗有名的依賴注入框架,可是這個框架基於反射來實現,對性能要求比較高,因此不適合android平臺。dagger基於預編譯的方式完成依賴注入。html
在使用Dagger前,首先要導入相關的包,若是使用Maven進行項目構建,則添加以下依賴便可:android
<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>
注意這裏第二個依賴dagger-compiler很重要,一開始沒有加入這個依賴的時候,一直在報以下錯誤:git
Module adapter for class XXXXX could not be loaded.Please ensure that code generation was run for this module.
緣由是,dagger的依賴注入是經過預編譯而非反射來完成的(可是dagger還有些地方用到了反射【具體是哪裏還有待研究】,dagger2徹底脫離了反射)。dagger-compiler庫中的函數完成編譯工程,在編譯的過程當中建立注入依賴所須要的類。github
Dagger中基本的三個註解:@Inject,@Provides,@Moudle,最最簡單的狀況須要使用@Inject,@Moudle。spring
示例場景:進影院看電影,首先要入座Seat,而後開始看電影watchMovie
入座---->Seat類app
public class Seat { @Inject public Seat() { System.out.println("*********prepare to seat************"); } public void seat(){ System.out.println("<----------- seating ---------->"); } }
看電影--->WatchMovie類框架
public class WatchMovie { @Inject Seat seat; public void watchMovie(){ seat.seat(); System.out.println("<----------- watching ---------->"); } }
Module類(這個類的做用待會兒說,如今先照着作就好啦!)ide
@Module( injects = MovieTest.class, library = true ) public class MovieModule { }
測試類--->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(); } }
運行結果:性能
*********prepare to seat************ <----------- seating ----------> <----------- watching ----------> Process finished with exit code 0
在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 ---------->"); } }
WatchMovie修改成以下:
public class WatchMovie { @Inject Seat seat; @Inject ILeave leave; public void watchMovie(){ seat.seat(); System.out.println("<----------- watching ---------->"); leave.leave(); } }
這裏增長了接口類型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(); } }
@Module的injects參數代表,MovieTest.class這個類須要經過MovieModule來完成依賴注入。
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類啦。
控制反轉自己的優勢:能夠解耦
方便測試
複用
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.