【问题标题】:Guice: How to change injection on runtime based on a (dynamic web property)Guice:如何基于(动态 Web 属性)在运行时更改注入
【发布时间】:2013-10-14 21:54:44
【问题描述】:

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

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

public interface RuleChecker{

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

然后我们有几个实现,我们的服务只接受超过 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{
    ...
}

但出于测试目的,我们希望在应用程序中实现一个 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;
     }
}

那么,Guice 有什么方法可以在运行时更改服务的注入吗?

例子:

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

--

目前,我已经找到了那些话题

Google Guice and varying injections at runtime 但我不知道这种供应商是否适合我的问题。

Guice runtime dependency parameters reinjection 这个很好的问题是在谈论类似的东西,但不是我正在寻找的形式。

guice: runtime injection/binding at command line 这是最接近我的问题,但他只在启动“运行时”时才这样做,并且不会随着时间的推移而改变它。

有什么帮助吗?

谢谢!

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

【问题讨论】:

  • 好问题。我一直在尝试做一些非常相似的事情。

标签: java dependency-injection inversion-of-control guice


【解决方案1】:

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

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.

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

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

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();
    }

    // [...]
}

【讨论】:

  • 我要做一个 PoC 来试试你的近似值 ;),希望几个小时后回来(现在是午餐时间 xD)
  • 更新主题,实现 POC 失败,请查看bitbucket.org/ramonboza/guicedynamicconfig
  • 设法让它在本地工作。我已经更新了帖子。您只需要重新加载依赖项并在您的提供程序中保持字段“类型”静态。
  • 这条线不是反对控制规则倒置吗? App.getInjector().injectMembers(this);
  • 在这个小sn-p中,它违反了IoC规则,因为它在服务内部。但是您可以使用提供者本身的这一行,例如。这样,服务就不会知道发生了什么。
猜你喜欢
  • 2013-06-29
  • 2017-05-28
  • 1970-01-01
  • 2015-04-17
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
相关资源
最近更新 更多