使用Guice:没有实现限制

时间:2016-07-13 23:11:08

标签: java dependency-injection annotations guice

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

MainClass:

 class MainClass {

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

TestModule:

 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。不幸的是,我认为我忽视了一些事情或误解了一些概念。

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

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

然而,当我尝试绑定时,它失败了。

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

联系

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

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

2 个答案:

答案 0 :(得分:1)

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

此时,Guice知道一个键:@Named("ABC") TempClientExternalFactory。没有Impl受约束。

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

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

  

没有<packageName>.TempWorkflowClientExternalFactoryImpl注释@com.google.inject.name.Named(value=ABC)的实施方式。

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

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

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

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

答案 1 :(得分:0)

PS:这是我第一次使用Guice。

我试图重现这个问题。但我无法做到。这是我的完整代码。如果我做的不同,请告诉我。

<强> TempClientExternalFactory

<div class="row">
  <div class="left">
    content
  </div>
  <div class="right">
    content
  </div>
  <div class="center">
    <h3>content</h3>
  </div>
  <div class="clear"></div>
</div>

<强> TempClientExternalFactoryImpl

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

<强> TempWorkflowClientExternal

public class TempClientExternalFactoryImpl implements TempClientExternalFactory {

  public TempClientExternalFactoryImpl(String swf_service, String domain) {

  }

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

<强>测试

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

<强> TestModule

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

此外,此stackoverflow问题与您提出的问题类似;

Error in binding: No implementation was bound - Guice