在运行时更改Guice绑定

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

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 } } 

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

更新这是我目前提出的,它不像我想的那么漂亮,所以我仍然在寻找反馈

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

你的版本几乎是完美的:你需要注入一些基于你编写的代码返回一个或另一个的对象,并且不需要辅助注入或类似的东西。 也就是说,你可以跳过一些样板:

 public class DomainProvider { // Just inject Providers directly without binding them explicitly. @Inject @Earth Provider earthDaoProvider; @Inject @Mars Provider marsDaoProvider; public Provider get(Domain domain){ switch (domain){ case EARTH: return earthDaoProvider; case MARS: return marsDaoProvider; } } public Provider get(String domain){ Domain parsedDomain = Domain.valueOf(domain.toUpperCase()); return get(parsedDomain); } } 

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

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

基本上,如果你绑定一个键Foo (对一个类,提供者, @Provides方法或实例),你会自动注入一个FooProvider而不需要额外的工作。 如果这是您想要的,那么提供商也是确保每次调用get新实例的好方法; 使用原始文件,对于您注入的任何给定DomainProvider,您将始终获得相同的EarthDao或MarsDao实例。 (如果你有像@Singleton这样的范围绑定,Guice也会尊重它; Provider只让Guice参与其中,而不是重用一个普通的旧Java引用。)

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