【问题标题】:Using Guice: No implementation bounded使用 Guice:没有实现限制
【发布时间】:2016-07-13 23:11:07
【问题描述】:

我是 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 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 类中的fac 对象被实例化为默认构造函数,而不是我想要关联的对象

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

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

【问题讨论】:

  • 如何构造Injector?您的TestModule 是否实际安装在喷油器中?如果你能提供一个minimal reproducible example 会有所帮助。
  • 是的,我已经在注射器中安装了 TestModule。由于代码包含使用凭证与 AWS SWF 的连接,因此我无法发布完整的示例。我已经用表示相同的注释替换了连接代码。其他一切都与代码中的一样。我还更新了最后的问题,其中提到了我要绑定的自动生成的类。

标签: java dependency-injection annotations guice


【解决方案1】:
bind(TempClientExternalFactory.class).annotatedWith(Names.named("ABC"))
    .toInstance(fac);

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

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

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

没有绑定带有@com.google.inject.name.Named(value=ABC) 注释的<packageName>.TempWorkflowClientExternalFactoryImpl 的实现。


据我所知,您有 3 个选项:

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

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

    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 并且工厂接口/impl 不太可能更改或直接调用,请抽象出工厂。依赖注入和工厂模式可能有重叠的职责,因此您可以使用 Guice 来返回正确的实现,而不是使用 Guice 返回工厂。

    这并不是说 Guice 永远不应该返厂;如果您的参数"123" 可能会更改,那么让 Guice 返回工厂是完全正确的。但是,如果该参数在您的代码库中是通用的,您可以将其抽象到您的 Guice Provider 中。

    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");
    }
    

【讨论】:

  • 嗨@Jeff,感谢您的回复。我尝试了前两个接近。如果可能的话,我想采用第一种方法,因为我以后需要通过模拟进行测试。无论如何,这两种方法都不起作用。当我尝试第一个方法时,我收到了错误 No implementation for &lt;packageName&gt;.TempWorkflowClientExternalFactory annotated with @com.google.inject.name.Named(value=ABC) was bound 。第二种方法也一样。如果您想从我这里获得更多信息,请告诉我
  • @alwaysANewbie 您能否仔细检查一下您对 TempWorkflowClientExternalFactory 与 TempClientExternalFactory 的使用情况?我刚刚意识到我们在问题或答案上都不一致。
  • 嗨@Jeff,抱歉打错了。我已经在上面的代码中进行了纠正(但是将错误保留在 TempWorkflowClientExternalFactoryImpl 的原始注入中,以确保问题的连续性)。我试图绑定 TempWorkflowClientExternalFactory。
  • 嗨@Jeff,我正在尝试注入 TempWorkflowClientExternalFactory。它类似于 GreeterWorkflowClientExternalFactory found [docs.aws.amazon.com/amazonswf/latest/awsflowguide/… here](页面的最后一个代码 sn-p)。只是提供这个,如果有帮助的话
【解决方案2】:

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();
  }
}

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

Error in binding: No implementation was bound - Guice

【讨论】:

  • TempClientExternalFactory、TempWorkflowClientExternal、TempClientExternalFactoryImpl 都是 AWS-SWF 自动生成的类/接口。您不能定义或修改这些类。
  • 我想我能够通过这个...通过使用@Inject TempClientExternalFactoryImpl 而不是界面...但是当我调用 fac.getClient()... 我会对此进行更多调查......如果这两个问题不相关,我会将我的发现作为答案发布
  • 我在这两个地方都使用了@Named 注释。我什至试过没有注释。如果没有使用注解,则绑定错误的对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 2018-08-30
  • 2011-08-04
  • 2015-11-08
相关资源
最近更新 更多