Guice 依賴綁定
連接綁定(Linked Bingdings)
連接綁定是 Guice 最基本的一種綁定方式。這種綁定方式我們需要在自己定義的 Module
的 configure()
中編寫綁定。如下所示:
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(Animal.class).to(Cat.class);
}
}
現在當調用 injector.getInstance(Animal.class)
時,就會返回一個 Cat
對象。
連接綁定也可以組成鏈式,如下:
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(Animal.class).to(Cat.class);
bind(Cat.class).to(PersianCat.class);
}
}
此時
注解綁定(Binding Annotations)
某些時候我們的一個接口可能有很多的實現,而此時我們在代碼的某個地方想讓這個接口綁定其中的某體格實現,這個時候直接使用連接綁定就不行了。
此時我們可以使用注解(Annotation)來綁定,我們可以使用自己定義的注解,舉例:
@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface Persian {}
這個注解中需要主要的是 @BindingAnnotation
這個地方,這是由 Guice 提供的,來標識這個注解就是用來標識綁定的,我們也可以稱其為綁定注解(Binging Annotation)。當一個對象被多個綁定注解所標識時,Guice 就會報錯
@Inject
@Persian
private Cat cat;
我們仍然需要指定綁定關系,如下:
bind(Cat.class)
.annotatedWith(Persian.class)
.to(PersianCat.class);
其實,如果沒有什么特殊需求的話,Guice 已經為我們提供了一種默認的注解來輔助我們進行對象綁定,@Named
。仍然以上述例子來說明:
@Inject
@Named("persian")
private Cat cat;
此時綁定關系可以這樣寫:
bind(Cat.class)
.annotatedWith(Names.named("persian"))
.to(PersianCat.class);
實例綁定(Instance Bindings)
顧名思義,直接使用實例而來進行綁定。通常這種綁定作用於沒有什么依賴和實現的對象上。
最普遍的應用大概就是一些參數變量的綁定了,直接 Copy 官方文檔的代碼:
bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza");
bind(Integer.class)
.annotatedWith(Names.named("login timeout seconds"))
.toInstance(10);
如果實例過於復雜,就不要使用這樣的方式綁定,因為這些代碼寫在 Module
的 configure()
中,會拖慢程序的啟動。稍后會說到,可以使用 @Provides
來代替。
@Provides 方法
當需要某種類型的對象時,就可以使用 @Provides
方法。這類方法必須定義在 Module
中,且用 @Provides
標識,如下:
public class AppModule extends AbstractModule {
protected void configure() {}
@Provides
PersianCat providePersianCat() {
PersianCat persianCat = new PersianCat();
persianCat.setName("Foo");
return persianCat;
}
}
這時當注入 PersianCat
類型對象時,就會從 providePersianCat()
方法中生成。
@Provides
方法也可以添加注解,這里就直接貼官方代碼了,不做贅述:
@Provides @PayPal
CreditCardProcessor providePayPalCreditCardProcessor(@Named("PayPal API key") String apiKey) {
PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
processor.setApiKey(apiKey);
return processor;
}
Provider 綁定(Provider Bindings)
當使用了太多 @Provides
方法綁定之后,Module
就會顯得臃腫不堪。這時可以試着將這些方法從 Module
中剝離出來,只要實現 Guice 提供的 Provider
的接口即可。
public interface Provider<T> {
T get();
}
Provider
接口只有一個 get()
方法,其實很簡單。直接把上述代碼移至此處。
public class PersianCatProvider implements Provider<PersianCat> {
public PersianCat get() {
PersianCat persianCat = new PersianCat();
persianCat.setName("Foo");
return persianCat;
}
}
最后如果需要,可以指定類型綁定到 Provider
:
bind(Cat.class).toProvider(PersianCatProvider.class);
構造方法綁定(Constructor Bindings)
有時候當綁定對象有多個構造方法時,我們可能需要指定某一個構造方法,這時可以使用構造方法綁定來達到目的。如下:
try {
bind(PersianCat.class).toConstructor(PersianCat.class.getConstructor(String.class));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
需要注意的是,這種綁定方式需要捕獲異常。
@ImplementedBy 與 @ProvidedBy
@ImplementedBy
注解用於簡化綁定配置,通常用於指定默認的實現類型。最常用的場景在於編寫 Dao 或者 Service 時,指定 Interface 的實現類。直接給出官方示例:
@ImplementedBy(PayPalCreditCardProcessor.class)
public interface CreditCardProcessor {
ChargeResult charge(String amount, CreditCard creditCard) throws UnreachableException;
}
等價於:
bind(CreditCardProcessor.class).to(PayPalCreditCardProcessor.class);
@ProvidedBy 也是顧名思義:
@ProvidedBy(DatabaseTransactionLogProvider.class)
public interface TransactionLog {
void logConnectException(UnreachableException e);
void logChargeResult(ChargeResult result);
}
等價於
bind(TransactionLog.class).toProvider(DatabaseTransactionLogProvider.class);