使用 Guice:没有实施限制

Using Guice: No implementation bounded

我是 Guice 新手。我将 Guice 与 AWS SWF 结合使用。我目前的结构如下:

主类:

 class MainClass {

   public static void main(String[] args) {
      Injector injector = Guice.createInjector(new ClientModule(param1, param2));
    injector = injector.createChildInjector(injector.getInstance(TestModule.class));
   }
 }

测试模块:

 class TestModule extends AbstractModule {

  @override
  protected void configure() {
  // create SWF service object
  // Register Workflow worker and Activity worker

   TempWorkflowClientExternalFactory fac = TempClientExternalFactoryImpl(swf_service, domain);
     bind(TempWorkflowClientExternalFactory.class).annotatedWith(Names.named("ABC")).toInstance(fac);  
  }
}

定义到class我想用的地方:

 class Test {

  @Inject
  @Named("ABC")
  TempWorkflowClientExternalFactoryImpl fac;


   public void method() {

    TempWorkflowClientExternal temp = fac.getClient("123");
    temp.callWorkflowMethod()       // This method is defined in SWF Workflow Activity class 
   }
}

但是在执行时出现以下错误:

No implementation for <packageName>.TempWorkflowClientExternalFactoryImpl annotated with @com.google.inject.name.Named(value=ABC) was bound

我需要在注入 TempWorkflowClientExternalFactory 的任何地方返回相同的对象。 我试着抬头看着 Guice wiki/FAQ。不幸的是,我想我忽略了一些东西或者误解了一些概念。

如果我在创建 fac 对象后在 configure 方法中使用以下代码而不是绑定,我的应用程序将按预期工作。

 TempWorkflowClientExternal temp = fac.getClient("123");
 temp.callWorkflowMethod() 

但是当我尝试绑定时,它失败了。

更新: 如果我在没有 annotatedWith 的情况下执行绑定,程序会执行,但我可以观察到绑定没有正确完成,因为 Test class 中的 fac 对象使用默认构造函数实例化而不是我想要关联的对象

其他详细信息:TempWorkflowClientExternalFactoryImpl、TempWorkflowClientExternalFactory、TempWorkflowClientExternal 也由 AWS-SWF 自动生成 classes。我不能修改它们的构造函数或在那些 classes 中添加任何注释。 Test.method() 将在满足特定业务逻辑条件时调用。

有人可以帮忙解决错误吗?

PS: 第一次使用Guice

我试图重现这个问题。但我做不到。这是我的完整代码。如果我正在做一些不同的事情,请告诉我。

TempClientExternalFactory

public interface TempClientExternalFactory {
  public TempWorkflowClientExternal getClient(String in);
}

TempClientExternalFactoryImpl

public class TempClientExternalFactoryImpl implements TempClientExternalFactory {

  public TempClientExternalFactoryImpl(String swf_service, String domain) {

  }

  public TempWorkflowClientExternal getClient(String in) {
    return new TempWorkflowClientExternal();
  }
}

TempWorkflowClientExternal

public class TempWorkflowClientExternal {
  public void callWorkflowMethod() {
    System.out.println("In callWorkflowMethod");
  }
}

测试

import com.google.inject.Inject;
import com.google.inject.name.Named;

class Test {

  @Inject
  @Named("ABC")
  TempClientExternalFactory fac;

  public void method() {
    TempWorkflowClientExternal temp = fac.getClient("123");
    temp.callWorkflowMethod();
    System.out.println("Success");
   }
}

测试模块

import com.google.inject.AbstractModule;
import com.google.inject.name.Names;

public class TestModule extends AbstractModule {
  @Override
  protected void configure() {
    TempClientExternalFactory fac = new TempClientExternalFactoryImpl(null, null);
    bind(TempClientExternalFactory.class).annotatedWith(Names.named("ABC")).toInstance(fac);
  }
}

应用程序

import com.google.inject.Guice;
import com.google.inject.Injector;

public class App {
  public static void main(String[] args) {
    Injector injector = Guice.createInjector(new TestModule());
    Test app = injector.getInstance(Test.class);
    app.method();
  }
}

此外,这个 Whosebug 问题看起来与您提出的问题相似;

bind(TempClientExternalFactory.class).annotatedWith(Names.named("ABC"))
    .toInstance(fac);

此时,Guice 知道一个键:@Named("ABC") TempClientExternalFactory。未绑定 Impl。

@Inject
@Named("ABC")
TempClientExternalFactoryImpl fac;

然而,在这里,您不请求 Factory,您请求 FactoryImpl。 Guice 不知道如何提供,所以它告诉你:

No implementation for <packageName>.TempWorkflowClientExternalFactoryImpl annotated with @com.google.inject.name.Named(value=ABC) was bound.


据我所知,你有 3 个选择:

  1. 请求工厂,而不是 FactoryImpl。这是最简单的解决方案,因为它可以帮助您实现 Guice/OOP 接口编码的最佳实践,而不是实现。您可以用任何实现替换测试中的工厂,包括来自模拟框架的实现。

    @Inject
    @Named("ABC")
    TempClientExternalFactory fac;
    
  2. @Named("ABC") FactoryImpl 绑定到实例,然后将 @Named("ABC") Factory 绑定到 @Named("ABC") FactoryImpl。这是一个很好的解决方案,以防万一您希望 classes 区分请求接口和请求实现 ,即使 它们解析为相同的 class 现在。否则,可能会导致代码混乱或不一致,因为接口和实现都将通过图形可用。

    bind(TempClientExternalFactoryImpl.class).annotatedWith(Names.named("ABC"))
        .toInstance(fac);
    bind(TempClientExternalFactory.class).annotatedWith(Names.named("ABC"))
        .to(Key.get(TempClientExternalFactoryImpl.class, Names.named("ABC"));
    
  3. 如果您需要提供的真正依赖项是 TempWorkflowClientExternal 并且工厂 interface/impl 不太可能更改或被直接调用,则将工厂抽象化。依赖注入和工厂模式可能有重叠的职责,因此与其使用 Guice return 工厂,不如使用 Guice return 正确的实现。

    None 这就是说 Guice 不应该 return 一个工厂;如果您的参数 "123" 可能会发生变化,那么让 Guice return 成为工厂是完全正确的。但是,如果该参数在您的代码库中是通用的,您可以将其抽象到您的 Guice 提供程序中。

    bind(TempWorkflowClientExternal.class).toProvider(
        new Provider<TempWorkflowClientExternal>() {
      TempClientExternalFactory fac = new TempClientExternalFactoryImpl(null, null);
      return fac.getClient("123");
    });
    

    ...或...

    @Provides TempWorkflowClientExternal getExternalFactory() {
      TempClientExternalFactory fac = new TempClientExternalFactoryImpl(null, null);
      return fac.getClient("123");
    }