我希望能够在运行时更改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);
答案 0 :(得分:13)
你的版本几乎是完美的:你需要注入一些根据你编写的代码返回一个或另一个的对象,并且不需要辅助注射或类似的东西那。也就是说,你可以跳过一些样板:
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。在the relevant Guice wiki topic上了解有关Guice Providers的更多信息。
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "@Earth IDao" and also "@Earth Provider<IDao>".
基本上,如果您将密钥Foo
(与类,提供程序,@Provides
方法或实例)绑定在一起,则automatically get to inject either a Foo
or Provider<Foo>
无需额外工作。提供商也是确保每次拨打get
时都能获得新实例的好方法,如果这是您想要的;使用原始文件,对于您注入的任何给定DomainProvider,您将始终获得相同的EarthDao或MarsDao实例。 (如果你有像@Singleton这样的范围绑定,Guice也会尊重它;提供者只是让Guice参与进来,而不是重用一个普通的旧Java引用。)
这意味着您可以跳过自定义的EarthDaoProvider和MarsDaoProvider,除非您确实需要对它们执行任何外部初始化 - 此时您可能最好不要调用bind(EarthDao.class).toProvider(EarthDaoProvider.class)
,因此准备工作也会在直接注入EarthDao。你也可以让DomainProvider直接通过调用相应Provider上的get
来返回一个IDao实例,并确保它每次都是一个新实例。