我想在我的应用程序中使用Guice for DI,我应该能够在运行时交换实现。下面提供了一个示例来说明要求:
class ValidationEngine {
public void validate(ValidationService vs) {}
}
class Client1_ValidationService implements ValidationService {}
class Client2_ValidationService implements ValidationService {}
上述实现之一应该绑定在运行时根据客户端名称验证函数,比如Client1或Client2
我想过像这样更改ValidationEngine:
class ValidationEngine {
@Inject
@Named("vServicee") ValidationService vs;
public void validate() {
vs.validate()
}
}
上述方法的问题是@Named注释的参数是静态的;事实上,注释不接受运行时值。 Guice还有其他方法可以解决这类问题吗?
答案 0 :(得分:1)
您可以通过它的构造函数将配置信息传递给Guice模块。
伪代码:
main() { // your main method
flags = parseFlags()
injector = guice.createInjector(new MyModule(flags.validator))
}
MyModule { // your guice module
constructor(validator): this.validator = validator;
configure() {
Class<ValidatorService> client_validator;
if this.validator == KNOWN_CLIENT1:
client_validator = Client1_ValidationService.class
else:
client_validator = Client2_ValidationService.class
bind(ValidationService.class).to(client_validator);
}
}
Guice警告不要这样做,因为它增加了你测试的表面积。 https://github.com/google/guice/wiki/AvoidConditionalLogicInModules
答案 1 :(得分:0)
您可以尝试使用Injector.createChildInjector为每个ValidationService
实施创建自己的注入器:
Injector client1Injector = injector.createChildInjector(new Module() {
@Override
public void configure(final Binder binder) {
binder
.bind(ValidationService.class)
.to(Client1_ValidationService.class);
}
});
ValidationEngine client1Engine =
client1Injector.getInstance(ValidationEngine.class)
但这意味着你必须以某种方式管理所有儿童注射器。
答案 2 :(得分:0)
1)通过注射器直接注射名称,如:
@Inject
private Injector injector;
public ValidationService getValidationServiceForClient(String clientName) {
return injector.getInstance(Key.get(ValidationService.class, Names.named(clientName)));
}
2)另一种方式:
public class ValidationServiceProviderImpl implements ValidationServiceProvider {
@Inject
@Named("ClientA")
private ValidationService clientAValidationService;
@Inject
@Named("ClientB")
private ValidationService clientBValidationService;
public ValidationService getValidationServiceForClient(String clientName) {
switch (clientName) {
case "ClientA": return clientAValidationService;
case "ClientB": return clientBValidationService;
}
return null; // return default validationService for any other client
}
}
public interface ValidationServiceProvider {
ValidationService getValidationServiceForClient(String clientName);
}
配置:
Injector injector = Guice.createInjector(new AbstractModule() {
protected void configure() {
bind(ValidationService.class)
.annotatedWith(Names.named("ClientA"))
.to(ClientA_ValidationService.class);
bind(ValidationService.class)
.annotatedWith(Names.named("ClientB"))
.to(ClientB_ValidationService.class);
bind(ValidationServiceProvider.class)
.to(ValidationServiceProviderImpl.class);
}
});
使用提供者的示例:
ValidationServiceProvider validationServiceFactory =
injector.getInstance(ValidationServiceProvider.class);
ValidationService clientA =
validationServiceFactory.getValidationServiceForClient("ClientA");
ValidationService clientB =
validationServiceFactory.getValidationServiceForClient("ClientB");
直接使用注射器的示例:
ValidationService clientA =
injector.getInstance(Key.get(ValidationService.class, Names.named("ClientA")));
ValidationService clientB =
injector.getInstance(Key.get(ValidationService.class, Names.named("ClientB")));