在运行时更改 Guice 绑定 [英] Changing Guice bindings at runtime

查看:29
本文介绍了在运行时更改 Guice 绑定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够在运行时更改 Guice 注入以支持基于用户输入的多次注入.这就是我想要实现的目标:

I would like to be able to change the Guice injections at runtime to support multiple injections based on user input. This is what I would like to achieve:

public interface IDao {
    public int someMethod();
}

public class DaoEarth implements IDao {
    @Override
    public int someMethod(){ ... }
}

public class DaoMars implements IDao {
    @Override
    public int someMethod(){ ... }
}

public class MyClass {
    @Inject
    private IDao myDao;

    public int myMethod(String domain) {
        //If Domain == Earth, myDao should be of the type DaoEarth

        //If Domain == DaoMars, myDao should be of the type DaoMars
    }
}

我正在考虑编写自己的提供程序,但我不知道如何使用该提供程序在运行时更改我的绑定.欢迎和感谢任何输入:)!

I was thinking of writing my own Provider, but I don't know how to use that provider to change my bindings at runtime. Any input is welcome and appreciated :)!

更新这是我目前想到的,它没有我想要的那么漂亮,所以我仍在寻找反馈

Update Here's what I currently came up with, it's not as pretty as I'd like, so I'm still looking for feedback

public class DomainProvider {
    @Inject @Earth
    private IDaoProvider earthDaoProvider;

    @Inject @Mars
    private IDaoProvider marsDaoProvider;

    public IDaoProvider get(Domain domain){
        switch (domain){
            case EARTH:
                return earthDaoProvider;
            case MARS:
                return marsDaoProvider;
        }
    }

    public IDaoProvider get(String domain){
        Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
        return get(parsedDomain);
    }
}

//MarsDaoProvider would be equivalent
public class EarthDaoProvider implements IDaoProvider {
    @Inject @Earth
    private IDao earthDao;

    public IDao getDao() {
        return earthDao;
    }
}

// This means that in "MyClass", I can do:
public class MyClass {
    @Inject
    private DomainProvider domainProvider;

    public int myMethod(String domain) {
        IDaoProvider daoProvider = domainProvider.get(domain);
        IDao dao = daoProvider.getDao();

        //Now "dao" will be of the correct type based on the domain
    }
}

//Of course elsewhere I have the bindings set like
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);

推荐答案

您的版本几乎是完美的:您将需要注入某种对象,根据您编写的代码返回一个或另一个,并且不需要辅助注射或类似的东西.也就是说,您可以跳过一些样板:

Your version is almost perfect as it is: You're going to need to inject some kind of object that returns one or the other based on code you write, and don't need assisted injection or anything like that. That said, you can skip some of the boilerplate:

public class DomainProvider {
    // Just inject Providers directly without binding them explicitly.
    @Inject @Earth Provider<IDao> earthDaoProvider;
    @Inject @Mars Provider<IDao> marsDaoProvider;

    public Provider<IDao> get(Domain domain){
        switch (domain){
            case EARTH:
                return earthDaoProvider;
            case MARS:
                return marsDaoProvider;
        }
    }

    public Provider<IDao> get(String domain){
        Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
        return get(parsedDomain);
    }
}
    

在这种情况下,您的 MyClass 将完全相同.这里,Provider 是一种方法通用接口 com.google.inject.Provider,或等效的内置 javax.inject.Provider 它扩展.在相关的 Guice wiki 主题上阅读有关 Guice 提供者的更多信息.

Your MyClass in that case would be exactly identical. Here, Provider is either the one-method generic interface com.google.inject.Provider, or the equivalent builtin javax.inject.Provider that it extends. Read more about Guice Providers on the relevant Guice wiki topic.

bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "@Earth IDao" and also "@Earth Provider<IDao>".

基本上,如果你绑定一个键 Foo(到一个类、提供者、@Provides 方法或实例),你自动注入 FooProvider 无需额外工作.提供程序也是确保每次调用 get 时都能获得新实例的好方法,如果这是您想要的;使用您的原始文件,您将始终为您注入的任何给定 DomainProvider 获得相同的 EarthDao 或 MarsDao 实例.(如果你有一个像 @Singleton 这样的作用域绑定,Guice 也会尊重它;Provider 只是让 Guice 参与进来,而不是重用一个普通的旧 Java 引用.)

Basically, if you bind a key Foo (to a class, provider, @Provides method, or instance), you automatically get to inject either a Foo or Provider<Foo> with no additional work. Providers are also a great way to ensure that you get a new instance with every call to get, if that's what you want; with your original, you'll always get the same instance of EarthDao or MarsDao for any given DomainProvider you inject. (If you have a scoped binding like @Singleton, Guice will respect that too; Provider just lets Guice get involved, rather than reusing a plain old Java reference.)

这意味着你可以跳过你的自定义 EarthDaoProvider 和 MarsDaoProvider,除非你真的需要对它们执行任何外部初始化——此时你最好调用 bind(EarthDao.class).toProvider(EarthDaoProvider).class) 所以在直接注入EarthDao时也会进行准备.您也可以通过在适当的 Provider 上调用 get 直接让 DomainProvider 返回一个 IDao 实例,并确保它每次都是一个新实例.

This means you can skip your custom EarthDaoProvider and MarsDaoProvider, unless you really need to perform any external initialization on them—at which point you'd probably be better off calling bind(EarthDao.class).toProvider(EarthDaoProvider.class) so the preparation also happens when injecting EarthDao directly. You could also just have DomainProvider return an IDao instance directly by calling get on the appropriate Provider, and be assured that it'll be a new instance every time.

这篇关于在运行时更改 Guice 绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆