假设我有这个界面:
public interface DbMapper{
}
然后这个实现:
public interface NameDbMapper extends DbMapper {
@SqlUpdate("insert into names (name) values (:name)")
void insert(@Bind("name") String name);
}
这个实现存在于一个模块中,所以我不知道编译时的所有DbMappers。我通过反思发现了DbMappers:
public class GuiceModule extends AbstractModule{
@Override
protected void configure() {
Reflections reflections = new Reflections("com.company");
Set<Class<? extends DbMapper>> dbMappers = reflections.getSubTypesOf(DbMapper.class);
for (Class<? extends DbMapper> dbMapper : dbMappers) {
Class<DbMapper> db = (Class<DbMapper>) dbMapper;
binder().bind(db).toProvider(DbMapperProvider.class);
}
}
然后我在我的提供者中实现了映射器:
public class DbMapperProvider implements Provider<DbMapper> {
private final User user;
@Inject
public DbMapperProvider(User user) {
this.user = user;
}
@Override
public DbMapper get() {
String jdbc = user.getJdbc();
DBI userSpecificDatabase = new DBI(jdbc, "user", "password");
//How to replace NameDbMapper.class here with the db variable in GuiceModule?
DbMapper dbMapper = userSpecificDatabase.onDemand(NameDbMapper.class);
return dbMapper;
}
}
User是@RequestScoped实例,因此我无法在GuiceModule中定期创建提供程序。注入用户但是如何在DbMapperProvider中传递哪个类DBI而不是硬代码NameDbMapper?
我已经尝试了http://google-guice.googlecode.com/git/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html中建议的方法,但无法使其发挥作用。
这里的目标是模块不应该编写自己的提供者,这是否可以实现?
答案 0 :(得分:7)
您可以绑定到提供程序实例,例如
for (Class<? extends DbMapper> dbMapper : dbMappers) {
bind(dbMapper).toProvider(new DbMapperProvider<>(db));
}
然后像这样修改你的提供者:
public class DbMapperProvider<T extends DbMapper> implements Provider<T> {
// Use field or method injection
@Inject
private Provider<User> user;
private final Class<T> type;
public DbMapperProvider(Class<T> type) {
this.type = type;
}
@Override
public T get() {
String jdbc = user.get().getJdbc();
DBI userSpecificDatabase = new DBI(jdbc, "user", "password");
DbMapper dbMapper = userSpecificDatabase.onDemand(type);
return dbMapper;
}
}