Google Guice结合模式
要創(chuàng)建綁定(Binding)對象,能夠繼承自AbstractModule類,然后覆蓋其configure方法,在方法調(diào)用bind()方法來指來定每一次綁定。這些方法帶有類型檢查,假設(shè)你使用了錯誤的類型編譯器就會報告編譯錯誤。假設(shè)你已經(jīng)寫好了Module類,則創(chuàng)建一個Module類對象作為參數(shù)傳遞給Guice.createInjector()方法用于創(chuàng)建一個注入器。
通過Module對象能夠創(chuàng)建鏈接綁定(linked bindings)、實(shí)例綁定(instance bindings)、@Provides methods、提供者綁定(provider bindings)、構(gòu)建方法綁定(constructor bindings)與無目標(biāo)綁定(untargetted bindings)。
這些綁定方式統(tǒng)稱為內(nèi)置綁定,相相應(yīng)的還有種及時綁定。假設(shè)在解析一個依賴時假設(shè)在內(nèi)置綁定中無法找到。那么Guice將會創(chuàng)建一個及時綁定。
一、鏈接綁定(LinkdedBindings)
鏈接綁定即映射一類型到它的實(shí)現(xiàn)類,比如映射TransactionLog接口到實(shí)現(xiàn)類DatabaseTransactionLog:
public class BillingModule extends AbstractModule {@Override protected void configure() {bind(TransactionLog.class).to(DatabaseTransactionLog.class);} }
這樣,當(dāng)你調(diào)用injector.getInstance(TransactionLog.class)方法,或者當(dāng)注入器碰到TransactionLog依賴時,就會使用DatabaseTransactionLog對象。鏈接是從一類型到它不論什么的子類型,這包含接口實(shí)現(xiàn)類,類的子類;所以例如以下映射也是能夠的:bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
而且鏈接綁定支持鏈?zhǔn)綄懛?#xff1a;
在這樣的情況下,當(dāng)請求一個TransactionLog類型對象時,注入器將返回一個MySqlDatabaseTransactionLog對象。
二、綁定注解
某些情況下你可能想為同一種類型設(shè)置多種綁定。這就能夠通過綁定注解來實(shí)現(xiàn),該注解與綁定的類型用于唯一結(jié)識一個綁定,
合在一起稱為Key。演示樣例:
這里關(guān)鍵的是@BindingAnnotation元注解,當(dāng)Guice描寫敘述到該注解時,就會把PayPal作為綁定注解。
然后在Module的configure方法中使用annotatedWith語句,例如以下:
bind(CreditCardProcessor.class).annotatedWith(PayPal.class).to(PayPalCreditCardProcessor.class);
這樣就把CreditCardProcessor映射到了PayPalCreditCardProcessor。
使用方法:
另一種情況,我們能夠使用Guice已經(jīng)定義好的@Named注解。比如:
要綁定一詳細(xì)名稱,使用Names.named()來創(chuàng)建一個實(shí)現(xiàn)傳給annotatedWith方法:
bind(CreditCardProcessor.class).annotatedWith(Names.named("Checkout")).to(CheckoutCreditCardProcessor.class);
由于編譯器不會對字符串進(jìn)行檢查,Guice建議我們少使用@Named注解,可是我個人覺得,僅僅要自己寫代碼時僅僅要名稱不要寫錯,
通過這樣的方法式是最easy為同一類型映射多個綁定的。這非常類似Spring中的實(shí)現(xiàn)方式,Spring的@Service,@Controller,@Repository不就能夠指定名稱嗎?
三、實(shí)例綁定(Instance Bindings)
通過實(shí)例綁定我們能夠?yàn)槟愁愋徒壎ㄒ粋€詳細(xì)的實(shí)例,這只適用于這些實(shí)例類型沒有其他依賴的情況,比如值對象:
bind(String.class).annotatedWith(Names.named("JDBC URL")).toInstance("jdbc:mysql://localhost/pizza");bind(Integer.class).annotatedWith(Names.named("login timeout seconds")).toInstance(10);
使用方式:
@Inject @Named("JDBC URL") private String urlGuice建議我們避免使用.toInstance來創(chuàng)建復(fù)雜的對象。由于這會延遲應(yīng)用啟動。類似地,能夠使用@Provides方法實(shí)現(xiàn)。
四、@Provides方法
當(dāng)使用@Provides方法創(chuàng)建對象時。該方法必須定義在Module類中。而且它必須加以@Provides注解。該方法的返回值類型就是被綁定的對象。
當(dāng)注入器須要該類型的實(shí)例時,它就會來調(diào)用該方法。
假設(shè)在@Provides方法上有@PayPal或@Named("Checkout")綁定注解。Guice以綁定注解優(yōu)先。Guice在調(diào)用@Provides方法之前會先解析該方法的依賴:
關(guān)于異常:
Guice不同意在@Provides方法中拋出異常。
假設(shè)有異常拋出。那么異常將會被包裝在ProvisionException對象中。
五、提供者綁定(Provider Bindings)
假設(shè)@Provides方法越來越復(fù)雜。我們可能會想把它們移到一個單獨(dú)的類中。一個提供者類實(shí)現(xiàn)了Provider接口。它是一個
用于提供值的簡單通用接口。
假設(shè)提供者實(shí)現(xiàn)類有其自己的依賴時,能夠通過在其構(gòu)造方法上加入@Inject注解進(jìn)行注入,以保證值安全返回。
最后使用.toProvider語句來綁定到提供者:
public class BillingModule extends AbstractModule {@Overrideprotected void configure() {bind(TransactionLog.class).toProvider(DatabaseTransactionLogProvider.class);} }
六、無目標(biāo)綁定
Guice同意我們創(chuàng)建綁定時不指定目標(biāo)類。也就是沒有to語句,這對于詳細(xì)類或者使用了@ImplementedBy或@ProvidedBy注解類型非常實(shí)用。比如:
bind(MyConcreteClass.class);
bind(AnotherConcreteClass.class).in(Singleton.class);
然而,在使用綁定注解時,我們依賴必須指定綁定目標(biāo)。即它是一個詳細(xì)類,比如:
bind(MyConcreteClass.class).annotatedWith(Names.named("foo")).to(MyConcreteClass.class); bind(AnotherConcreteClass.class).annotatedWith(Names.named("foo")).to(AnotherConcreteClass.class).in(Singleton.class);
七、構(gòu)造方法綁定
有些時候你可能須要將某一類型綁定到任一構(gòu)建方法,比如在@Inject注解無法加入到目標(biāo)類構(gòu)造方法,其原因可能是這個類是
第三方提供的。或者說該類有多個構(gòu)建方法參與依賴注入。此時@Provides方法是解決問題的最好方案,由于它能夠明白指定
調(diào)用哪個構(gòu)造方法。并且不須要使用反射機(jī)制。
可是使用@Provides方法在某些地方有限制,比如:手動創(chuàng)建對象不能在AOP中使用。
正是由于這個原因,Guice使用了toConstructor()進(jìn)行綁定。這須要我們使用反射來選擇構(gòu)造方法與處理異常。
public class BillingModule extends AbstractModule {@Override protected void configure() {try {bind(TransactionLog.class).toConstructor(DatabaseTransactionLog.class.getConstructor(DatabaseConnection.class));} catch (NoSuchMethodException e) {addError(e);}} }
上這個樣例中DatabaseTransactionLog類必須有一個帶DatabaseConnection參數(shù)的構(gòu)造方法,該構(gòu)造方法中不須要使用@Inject注解Guice會自己主動調(diào)用該構(gòu)造方法。每一條toConstructor()語句創(chuàng)建的綁定。其作用域是獨(dú)立的,假設(shè)你創(chuàng)建了多個單例綁定而且使用目標(biāo)類的同一個構(gòu)造方法,每個綁定還是擁有各自的實(shí)例。
八、及時綁定
當(dāng)注入器須要某一類型實(shí)例的時候。它須要獲取一個綁定。在Module類中的綁定叫做顯示綁定,僅僅要它們可用,注入器就能夠使用它們。假設(shè)須要某一類型實(shí)例,但它又不是顯示綁定。那么注入器將試圖創(chuàng)建一個及時綁定(Just-In-Time bindings),它也被稱為JIT綁定與隱式綁定。
可用于創(chuàng)建及時綁定的情況例如以下:
a.有一個合適的構(gòu)建方法,即非私有。不帶參數(shù)或者標(biāo)有@Inject注解的構(gòu)造方法,比如:
Guice不會創(chuàng)建內(nèi)部類實(shí)例除非它有static修飾符,由于內(nèi)部類含有一個指向外問類的隱式引用,而這個隱式引用無法注入。
b. @ImplementedBy
@ImplementedBy注解于用告訴注入器某類型的缺省實(shí)現(xiàn)類型是什么,這與鏈接綁定非常相似。
為某一類型綁定一子類型例如以下:
@ImplementedBy(PayPalCreditCardProcessor.class)等效于以下的bind()語句:
bind(CreditCardProcessor.class).to(PayPalCreditCardProcessor.class);
假設(shè)某一類型即有bind()語句又有@ImplementedBy注解。則bind()語句優(yōu)先。使用@ImplementedBy請小心,由于它為接口加入了編譯時依賴。
c. @ProvidedBy
@ProvidedBy注解用于告訴注入器。Provider類的實(shí)現(xiàn)是什么,比如:
@ProvidedBy(DatabaseTransactionLogProvider.class) public interface TransactionLog {void logConnectException(UnreachableException e);void logChargeResult(ChargeResult result); }這等價于bind(TransactionLog.class).toProvider(DatabaseTransactionLogProvider.class);
類似@ImplementedBy注解,假設(shè)某個類型既使用了bind()語句,又使用了@ProvidedBy注解。然后,bind()聲明優(yōu)先。
版權(quán)聲明:本文博主原創(chuàng)文章,博客,未經(jīng)同意不得轉(zhuǎn)載。
轉(zhuǎn)載于:https://www.cnblogs.com/mengfanrong/p/4829214.html
總結(jié)
以上是生活随笔為你收集整理的Google Guice结合模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP5.6.6上运行 ecshop 2
- 下一篇: linux网口驱动实现(待续)