[英]Bindings in Guice: Compile time dependencies
在探索Guice時,我對依賴項的注入方式提出了疑問。
根據我的理解,DI的一個重要方面是,依賴性是已知的並且是在運行時注入的。
在Guice中,要注入依賴項,我們需要添加綁定或實現提供程序。 添加依賴項需要一個類對象,該類對象在該類上添加編譯時依賴項。 避免這種情況的一種方法是將其實現為提供程序,並讓提供程序使用反射來動態加載類。
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(CreditCardProcessor.class).toProvider(
BofACreditCardProcessorProvider.class);
bind(CreditCardProcessor.class).annotatedWith(BofA.class).toProvider(
BofACreditCardProcessorProvider.class);
bind(CreditCardProcessor.class).annotatedWith(Amex.class).toProvider(
AmexCreditCardProcessorProvider.class);
}
@Provides
PaymentProcessor createPaymentProcessor() {
return new PayPalPaymentProcessor();
}
@Provides
PayPalPaymentProcessor createPayPalPaymentProcessor() {
return new PayPalPaymentProcessor();
}}
是否有理由為Guice選擇類對象而不是類名? 這可能已經刪除了編譯時依賴性嗎?
如果您的接口和實現是在同一個依賴項中定義的(即,在同一個JAR文件中),那么無論您是否使用Guice,您都已經對實現具有硬構建依賴性。
基本上,只要你有:
public final class MyClass {
public void doSomething(Foo foo);
}
然后要編譯MyClass
, Foo
的定義需要在編譯時類路徑上。
解決此問題的方法是將接口與實現分開。 例如,如果Foo
是一個接口,而FooImpl
是執行它,你會把FooImpl
在不同的依賴性(即不同的JAR文件)從Foo
。
現在,假設您在Maven中有兩個子項目:
foo-api/
pom.xml
src/main/java/com/foo/Foo.java
foo-impl/
pom.xml
src/main/java/com/foo/FooImpl.java
綁定Foo
的Guice模塊應該在哪里生活? 它不應該存在於foo-api
項目中,它應該與FooImpl
一起生活在foo-impl
項目中。
現在假設你有一個單獨的Foo
實現(讓我們稱之為SuperFoo
),你的項目需要一個Foo
,但它可能是FooImpl
或SuperFoo
。
如果我們讓SuperFoo
成為自己的項目:
super-foo/
pom.xml
src/main/java/com/super/foo/SuperFoo.java
src/main/java/com/super/foo/SuperFooModule.java
現在您的所有應用程序代碼都可以簡單地@Inject Foo
並使用foo。 在main()
方法中(或者在創建Injector
任何地方),您需要決定是安裝FooModule
(來自foo-impl
)還是SuperFooModule
(來自super-foo
)。
這是可以保證反思的地方。 例如,您可以使用配置標志foo_module
,該標志可以設置為"com.foo.FooModule"
或"com.super.foo.SuperFooModule"
。 您可以使用以下代碼決定安裝哪一個:
public static void main(String[] args) {
Config config = parseConfig(args);
List<Module> modules = new ArrayList<>();
modules.add(...); // application modules
String fooModuleName = config.get("foo_module");
Class<? extends Module> moduleClass =
Class.forName(fooModuleName).asSubclass(Module.class);
modules.add(moduleClass.newInstance());
Injector injector = Guice.createInjector(modules);
injector.getInstance(MyApplication.class).run();
}
當然,您也可以使用您喜歡的任何其他機制來選擇要安裝的模塊。 在許多情況下,您甚至不想反復這樣做,只需在更改構建依賴項的同時更改代碼即可。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.