使用 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 个选择:
请求工厂,而不是 FactoryImpl。这是最简单的解决方案,因为它可以帮助您实现 Guice/OOP 接口编码的最佳实践,而不是实现。您可以用任何实现替换测试中的工厂,包括来自模拟框架的实现。
@Inject
@Named("ABC")
TempClientExternalFactory fac;
将 @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"));
如果您需要提供的真正依赖项是 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");
}
我是 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 个选择:
请求工厂,而不是 FactoryImpl。这是最简单的解决方案,因为它可以帮助您实现 Guice/OOP 接口编码的最佳实践,而不是实现。您可以用任何实现替换测试中的工厂,包括来自模拟框架的实现。
@Inject @Named("ABC") TempClientExternalFactory fac;
将
@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"));
如果您需要提供的真正依赖项是 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"); }