使用 Google Guice 在运行时注入依赖项
Inject Dependencies at runtime using Google Guice
我正在考虑在我的应用程序中使用 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中还有其他方法可以解决这类问题吗?
您可以尝试使用 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)
但这意味着您必须以某种方式管理所有子注射器。
您可以通过它的构造函数将配置信息传递给您的 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) 直接通过注入器注入名称,例如:
@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")));
我正在考虑在我的应用程序中使用 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中还有其他方法可以解决这类问题吗?
您可以尝试使用 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)
但这意味着您必须以某种方式管理所有子注射器。
您可以通过它的构造函数将配置信息传递给您的 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) 直接通过注入器注入名称,例如:
@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")));