簡體   English   中英

Guice中的綁定:編譯時間依賴性

[英]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);
}

然后要編譯MyClassFoo的定義需要在編譯時類路徑上。

解決此問題的方法是將接口與實現分開。 例如,如果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 ,但它可能是FooImplSuperFoo

如果我們讓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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM