使用Google Guice在运行时注入依赖项

时间:2016-08-09 14:33:35

标签: 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还有其他方法可以解决这类问题吗?

3 个答案:

答案 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")));