Java Guice:如何根据(动态 Web 属性)更改运行时注入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19358487/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 16:27:11  来源:igfitidea点击:

Guice: How to change injection on runtime based on a (dynamic web property)

javadependency-injectioninversion-of-controlguice

提问by RamonBoza

The following is an approximation of the problem I'm facing.

以下是我面临的问题的近似值。

Think we have a password validator with some rules.

认为我们有一个带有一些规则的密码验证器。

public interface RuleChecker{

    //Checks for a password strenght, returns 10
    //for strong or 0 for soft password.
    int check(String pass);
}

And then we have several implementations, our service will only accept the password if it is over 8 score.

然后我们有几个实现,我们的服务只接受超过 8 分的密码。

public class NoCheck implements RuleChecker {
    public int check(String pass){return 10;}
}

public class LengthCheck implements RuleChecker{
    ...
}
public class AlphanumericCheck implements RuleChecker{
    ...
}
public class AlphaAndLenghtCheckAdapter implements RuleChecker{
    ...
}

But for testing purposes, we want to implement a webservice within the application where we can "admin" those rules, and select which ones to have.

但出于测试目的,我们希望在应用程序中实现一个 Web 服务,我们可以在其中“管理”这些规则,并选择要拥有哪些规则。

public class PasswordCheckService{

     private RuleChecker checker;

     @Inject
     public PasswordCheckService(final RuleChecker checker){
         this.checker = checker;
     }

     public boolean checkPassword(String password){
         return checker.check(password) > 8;
     }
}

So, is there any way in Guice, to change at runtime, the injection a service has?

那么,Guice 有没有办法在运行时改变服务的注入呢?

Example:

例子:

We started the application and by default LengthCheck is selected and injected on the application, at the website we select the NoCheck checkbox and save options, which is stored into the database, can I configure Guice to automatically change the bean the service had injected before? so from now and on there will be no checks on new passwords?

我们启动了应用程序,默认情况下 LengthCheck 被选中并注入到应用程序中,在网站上我们选择 NoCheck 复选框并保存选项,这些选项存储到数据库中,我可以配置 Guice 以自动更改服务之前注入的 bean 吗?所以从现在开始将不再检查新密码?

--

——

As for now, I have found those topics

至于现在,我找到了那些话题

Google Guice and varying injections at runtimeBut i dont know if that kind of providers fits my problem.

Google Guice 和运行时不同的注入但我不知道这种提供者是否适合我的问题。

Guice runtime dependency parameters reinjectionThat nice question is talking something similar, but not what I'm looking form.

Guice 运行时依赖参数重新注入这个很好的问题是在谈论类似的东西,但不是我正在寻找的形式。

guice: runtime injection/binding at command lineThis is the closest to my problem but he only does on starting "runtime" and does not change it over the time.

guice:命令行中的运行时注入/绑定这是最接近我的问题,但他只在启动“运行时”时执行,并且不会随着时间的推移而更改。

Any helps?

有帮助吗?

Thank you!

谢谢!

Using the tip of the first comment I implemented this POC but still does not works, if you change select another button the service bean is not updated. https://bitbucket.org/ramonboza/guicedynamicconfig

使用第一条评论的提示,我实现了这个 POC,但仍然不起作用,如果您更改选择另一个按钮,则服务 bean 不会更新。 https://bitbucket.org/ramonboza/guicedynamicconfig

采纳答案by Vianney Dupoy de Guitard

Create a provider for each field type (login, password, birth date...), with a parameter to change the implementation to return.

为每个字段类型(登录名、密码、出生日期...)创建一个提供程序,并带有一个参数来更改要返回的实现。

public class MyModule extends AbstractModule {

    public void configure() {
       bind(RuleChecker.class).annotatedWith(named("password")).toProvider(PasswordRuleCheckerProvider.class);
       bind(RuleChecker.class).annotatedWith(named("login")).toProvider(LoginRuleCheckerProvider.class);
    }
}

public static class PasswordRuleCheckerProvider implements Provider<RuleChecker> {

    private static CheckType type = CheckType.ALPHANUMERIC;
    // static type setter.

    public RuleChecker get() {
        // it would even be better if you could use singletons here.
        switch(type) {
            case LENGTH:
                return new LengthCheck();
            case ALPHANUMERIC:
                return new AlphanumericCheck();
            case ALPHALENGTH:
                return new AlphaAndLenghtCheckAdapter();
            case NONE:
            default:
                return NoCheck();
        }
    }
}
// Almost same provider for your LoginRuleCheckerProvider. You could do something generic.

In your admin section you change "type" value, so your rules will change. It can affect a limited set of fields, thanks to the annotations. For instance : PasswordRuleCheckerProvider.setType(CheckType.LENGTH);. Will only affect fields with @Named('password').

在您的管理部分,您更改“类型”值,因此您的规则将更改。由于注释,它可以影响一组有限的字段。例如:PasswordRuleCheckerProvider.setType(CheckType.LENGTH);。只会影响带有@Named('password').

You have to declare your fields and services like this :

您必须像这样声明您的字段和服务:

public abstract class DynamicService {
    protected void updateService() {
        // Reinject with the new implementations the members.
        App.getInjector().injectMembers(this);
    }
}

public class PasswordCheckService extends DynamicService  {
    @Inject
    @Named("password")
    private RuleChecker passwordChecker;

    public void changePasswordCheckType(CheckType type) {
        PasswordRuleCheckerProvider.setType(type);
        // Reinject, so you have your new implementation.
        updateService();
    }

    // [...]
}