通過Guice學(xué)習(xí)理解依賴注入_第1頁
通過Guice學(xué)習(xí)理解依賴注入_第2頁
通過Guice學(xué)習(xí)理解依賴注入_第3頁
通過Guice學(xué)習(xí)理解依賴注入_第4頁
通過Guice學(xué)習(xí)理解依賴注入_第5頁
已閱讀5頁,還剩1頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

通過Guice學(xué)習(xí)理解依賴注入提及依賴注入(DependencyInjection),想必童鞋們會想到MartinFowler的《InversionofControlContainersandtheDependencyInjectionpattern》,而本文正是通過Guice來學(xué)習(xí)理解依賴注入的實現(xiàn)。其次筆者在學(xué)習(xí)依賴注入之初(未曾學(xué)習(xí)《InversionofControlContainersandtheDependencyInjectionpattern》時),亦曾受"控制反轉(zhuǎn)”(InversionofControl)和"依賴注入"(DependencyInjection)二概念所蒙蔽。因此為打消各位童鞋學(xué)習(xí)顧慮,此處給出明確說明,在MartinFowler未成《InversionofControlContainersandtheDependencyInjectionpattern》一文前,開源社區(qū)幾位輕量級容器作者稱其為"控制反轉(zhuǎn)”(InversionofControl,簡稱IoC),但由于該名稱太泛,常常會讓人迷惑,因此MartinFowler和多位IoC愛好者討論后,決定將這個模式叫做"依賴注入"(DependencyInjection)。這里可以簡單理解為"控制反轉(zhuǎn)”和"依賴注入”只是稱謂的不同罷了。依賴示例MartinFowler在《InversionofControlContainersandtheDependencyInjectionpattern》一文中提供了—提供一份電影清單組件的例子,偽代碼清單1如下:/*finder服務(wù)接口*/publicinterfaceMovieFinder(ListfindAll();}/*finder服務(wù)的消費者*/publicclassMovieLister(publicMovie[]moviesDirectedBy(Stringarg)(ListallMovies=finder.findAll();for(Iteratorit=allMovies.iterator();it.hasNext();){Moviemovie=(Movie)it.next();if(!movie.getDirector().equals(arg))it.remove();}return(Movie[])allMovies.toArray(newMovie[allMovies.size()]);}/*指向具體服務(wù)類型的實體對象*/privateMovieFinderfinder;publicMovieLister(){finder=newColonDelimitedMovieFinder("movies1.txt");}}清單1從清單1的偽代碼中我們可以看出在涉及到實際尋找影片時,MovieLister類就會涉及到MovieFinder的某個具體子Finder(電影查找器)類,MovieLister類會在構(gòu)造子中直接創(chuàng)建MovieFinder的實例,因此MovieLister類和MovieFinder會存在如圖1所示的依賴關(guān)系:—nlnterfacenMovieLlster MovjeF|nder■、'-.creates" !、AMovieFinderlmp^圖1圖1中MovieLister類既依賴于MovieFinder接口,又依賴于MovieFinder接口的具體實現(xiàn)類(ColonDelimitedMovieFinder),這就會使得電影清單組件會因為在不同的應(yīng)用場景中它所依賴的電影查找器可能是千差萬別的。所以我們希望MovieLister類只依賴于接口,因此我們就需要有一種機制能同時滿足如下兩個要求:解除電影清單中對MovieFinder類型的編譯時依賴;在運行時為電影清單提供所需的MovieFinder類型實例。換句話說就是在運行時建立電影清單組件中對MovieFinder所需的依賴關(guān)系,從而使其電影清單組件在編譯時對MovieFinder的依賴推遲到運行時。依賴關(guān)系在面向?qū)ο蟮某绦蛑惺菑V泛存在的,只要A類型中用到了B類型實例,那么A就依賴于B。依賴示例談到的內(nèi)容是把概念抽象到了服務(wù)消費者和服務(wù)提供者的角度,這也符合現(xiàn)在SOA的設(shè)計思路。從另一種抽象方式上來看,可以把電影清單看成我們要構(gòu)建的主系統(tǒng),而MovieFinder是系統(tǒng)中的plugin,主系統(tǒng)并不強依賴于任何一個插件,但一旦插件被加載,主系統(tǒng)就應(yīng)該可以準(zhǔn)確調(diào)用適當(dāng)插件的功能。其實不管是面向服務(wù)的編程模式,還是基于插件的框架式編程,為了實現(xiàn)松耦合(服務(wù)消費者和提供者之間的或者框架和插件之間的),都需要在必要的位置實現(xiàn)面向接口編程,在此基礎(chǔ)之上,還應(yīng)該有一種可行的機制實現(xiàn)具體類型之間的運行時綁定,這就是依賴注入(DependencyInjection)所要解決的問題。依賴注入的幾種形式依賴注入(DependencyInjection)模式的基本思想是用一個單獨的對象(裝配器)來獲得MovieFinder的一個合適的實現(xiàn),并將其實例賦給MovieLister類的一個字段。這樣一來,我們就得到了圖2所示的依賴圖:■=lnterface?MovieFinder圖2:引入依賴注入器之后的依賴關(guān)系依賴注入的形式主要有三種,分別將它們叫做構(gòu)造子注入(ConstructorInjection)、設(shè)值方法注入(SetterInjection)和接口注入(InterfaceInjection)。下面將使用GoogleGuice(后面文章中都以Guice簡寫)來演示構(gòu)造子、設(shè)值方法注入方式:首先請允許我簡單的介紹下Guice,它是2007年由兩位軟件大師BobLee和KevinBourrillion基于Java5開發(fā)的一個輕量級的開放源代碼的依賴注入框架。它非常小而且很快,它是類型安全的,它能夠?qū)?gòu)造函數(shù)、屬性和方法進行注入。使用Guice進行基本注入時首先需要告訴Guice注入點(也就是給需要注入的類添加@Inject注解),其次告訴Guice注入的類需要的依賴項,最后是使用Injector啟動應(yīng)用程序。構(gòu)造子注入使用Guice構(gòu)造子注入方式將MovieFinder實例注入MovieLister類,MovieLister類必須聲明一個構(gòu)造子,并在其構(gòu)造子上添加@Inject注解,偽代碼清單2如下:publicclassMovieLister...@InjectpublicMovieLister(MovieFinderfinder)(this.finder=finder;}清單2現(xiàn)在Guice知道MovieLister需要一個MovieFider,當(dāng)然它還需要知道為其提供一個什么樣的MovieFinder。代碼清單3包含一個Module,這是一個特殊的類,用于告訴Guice各個接口對應(yīng)的實現(xiàn)。偽代碼清單3如下:publicclassMovieModuleimplementsModule(@Overridepublicvoidconfigure(Binderbinder)(binder.bind(MovieFinder.class).to(ColonDelimitedMovieFinder.class);}}清單3Guice中模塊就是一個具有某種單實例對象方法的接口,Guice傳遞給模塊的Binder用于告訴Guice您想如何構(gòu)造對象。每次調(diào)用bind都會創(chuàng)建一個綁定,Guice將使用綁定集解析注入請求?,F(xiàn)在使用Injector類啟動Guice,代碼清單4如下:publicclasstestMovie(){publicstaticvoidmain(Stringargs){Injectorinjector=Guice.createInjector(newMovieModule());MovieFinderfinder=injector.getInstance(ColonDelimitedMovieFinder.class);MovieListermovieLister=newMovieLister(finder);movieLister.moviesDirectedBy("inception");}}清單4代碼清單4中為了獲取注入器,需要在Guice類上調(diào)用createInjector,向createInjector傳遞一個模塊列表,用于配置它本身。擁有注入器后,使用getInstance向它請求對象,傳遞您想返回的.class。設(shè)值方法注入Guice對MovieLister進行設(shè)值方法注入(Spring框架的忠實用戶可以將此方法視為“setter注入”)時,需要先為它定義一個設(shè)值方法,該方法接受類型為MovieFinder的參數(shù),偽代碼清單5如下:publicclassMovieLister{privateMovieFinderfinder;@InjectpublicvoidsetMovieFinder(MovieFinderfinder){this.finder=finder;}}清單5從偽代碼清單5可以看出Guice設(shè)值方法注入其實也是給設(shè)值方法添加@Inject注解。類似的Guice需要知道MovieLister需要一個MovieFider,當(dāng)然它還需要知道為其提供一個什么樣的MovieFinder。這一步和使用Guice進行構(gòu)造子注入完全一樣,可參考清單3.現(xiàn)在使用Injector類啟動Guice,代碼清單6如下:publicclasstestMovie(){publicstaticvoidmain(Stringargs){Injectorinjector=Guice.createInjector(newMovieModule());MovieFinderfinder=injector.getInstance(ColonDelimitedMovieFinder.class);MovieListermovieLister=newMovieLister();movieLister.setMovieFinder(finder);movieLister.moviesDirectedBy("inception");}}清單6接口注入除了構(gòu)造子、方法兩種注入技術(shù),還可以在接口中定義需要注入的信息,并通過接口完成注入。首先需要定義一個接口,組件的注入將通過這個接口進行。在本示例中,這個接口的用途是將一個MovieFider實例注入繼承了該接口的對象。接口定義代碼清單7如下:publicinterfaceInjectFinder{voidinjectFinder(MovieFinderfinder);清單7接下來這個接口應(yīng)該由提供MovieFider接口的人一并提供。因此任何想要使用MovieFider實例的類(例如MovieLister類)都必須實現(xiàn)這個接口。偽代碼清單8如下:publicclassMovieListerimplementsInjectFinderprivateMovieFinderfinder;publicvoidinjectFinder(MovieFinderfinder)(this.finder=finder;}}清單8然后使用類似的方法將文件名注入MovieFider的實現(xiàn)類,偽代碼清單9如下:publicinterfaceInjectFilename(voidinjectFilename(Stringfilename);}publicclassColonDelimitedMovieFinderimplementsMovieFinder,InjectFilename(privateStringfilename;publicvoidinjectFilename(Stringfilename)(this.filename=filename;}@OverridepublicListfindAll()(returnnull;}}清單9現(xiàn)在,還需要用一些配置代碼將所有的組件實現(xiàn)裝配起來。這里將配置好的MovieLister對象保存在名為lister的字段中,偽代碼清單10如下:publicclassIfaceTester(privateMovieListerlister;privatevoidconfigureLister()(ColonDelimitedMovieFinderfinder=newColonDelimitedMovieFinder();finder.injectFilename("movies1.txt");lister=newMovieLister();lister.injectFinder(finder);}/*測試方法*/publicvoidtestIface()(configureLister();Movie[]movies=lister.moviesDirectedBy("SergioLeone");assertEquals("OnceUponaTimeintheWest",movies[0].getTitle());}}清單10從接口注入的實現(xiàn)不難看出,容器所要做的就是根據(jù)接口定義調(diào)用其中的Inject方法完成注入過程,總的原理和構(gòu)造子、設(shè)值方法注入?yún)^(qū)別不大,只是在表現(xiàn)形式上有些不同;其次考慮到Guice未提供接口注入支持,因此本文無法直接只用Guice來實現(xiàn)接口注入,這里是通過Avalon架構(gòu)來實現(xiàn)此種接口注入,因此如有興趣的童鞋可以從/dist/avalon/framework/獲取相關(guān)的資料學(xué)習(xí)。至此依賴注入的三種基本形式基本介紹完畢,同時從依賴注入的實現(xiàn)上不難看出,依賴注入它消除了MovieLister類對具體MovieFider實現(xiàn)類的依賴。這樣一來,就可以把MovieLister作為一個服務(wù)提供者獨立組件提供出來,讓服務(wù)消費者根據(jù)自己的環(huán)境插入一個合適的MovieFider實現(xiàn)即可。后記:文中只使用到了Guice3種基本依賴注入方式中的構(gòu)造子注入和方法注入,其實Guice還支持field注入。其次在Guice的依賴注入中,Guice只關(guān)心@Inject注解,因此基于方法和field的依賴注入可以是基于私有方法、field的注入(但不推薦對私有field進行注入,這樣會影響可測試性)。而更

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論