如何使用Guice将参数传递给Provider?

5

假设我有这样一个接口:

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

用户是一个@RequestScoped实例,因此我无法在GuiceModule中正常创建提供程序。注入用户可以工作,但是我如何传递哪个类DBI应该使用而不是硬编码NameDbMapper在DbMapperProvider中?
我尝试了http://google-guice.googlecode.com/git/javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html中建议的方法,但无法使其正常工作。
这里的目标是模块不应编写自己的提供程序,这可行吗?
1个回答

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

我收到了“无法访问作用域对象。我们当前要么不在HTTP Servlet请求内,要么您可能忘记为此请求应用com.google.inject.servlet.GuiceFilter作为Servlet过滤器。”出于某种原因,Guice尝试在初始化期间急切地创建实例? - jontejj
1
当然可以。您可以注入一个Provider<User>。 - Tavian Barnes
哇!非常感谢这个。+1 - jontejj
我的天啊。这个能用,我真的感到冷飕飕的了。你让我领略了Guice的精妙。 (特别是你可以调用new Object,还能注入它的字段/方法) - durron597
@durron597 实际上有很多情况是这样的。requestInjection()toInstance() 是另外两个例子。请参考这里获取更多信息。 - Tavian Barnes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接