我是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()。
有人可以帮忙解决错误吗?
答案 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)
的实施方式。
据我所知,你有三个选择:
请求工厂,而不是FactoryImpl。这是最简单的解决方案,因为它可以帮助您使用Guice / OOP编写接口的最佳实践,而不是实现。您可以将测试中的Factory替换为任何实现,包括来自模拟框架的实现。
@Inject
@Named("ABC")
TempClientExternalFactory fac;
将@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"));
如果您需要提供的真正依赖项是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问题与您提出的问题类似;