java - 使用 guice 将运行时参数传递给构造函数

标签 java dependency-injection guice

如果我有以下类(class):

public class ObjectDAOMongoDBImpl<T> extends GenericDAOMongoDBImpl<T, ObjectId> implements ObjectDAO<T> {
    public ObjectDAOMongoDBImpl(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) {
        super(entityClass, mongo, morphia, dbName);
    }
}

在运行时提供 entityClass - 我如何使用 guice 将所述类型绑定(bind)到接口(interface)?

public class RunnerModule extends AbstractModule {      
    @Override
    protected void configure() {
        bind(GenericDAO.class).to(ObjectDAOMongoDBImpl.class);
    }
}

public class Runner<T, V> {
    GenericDAO<T, V> dao;

    @Inject
    public Runner(GenericDAO<T, V> dao) {
        this.dao = dao;
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new RunnerModule());
        injector.getInstance(Runner.class);
    }
}

可以将 mongomorphiadbName 定义为 RunnerModule 的文字(有没有更干净的方式?),但直到运行时我才知道 entityClass 是什么。

最佳答案

这不是 Guice 惯用的做法,也不是它的主要关注点。

jfpoilpret 已经说了所有可以说的,但我想从另一个方向来解决这个问题,您可以选择(可能)通过失去类型安全来解决您的问题。

因此,在您的代码中,您要求 Guice 获取 Runner<T, V> 的一个实例像这样上课

injector.getInstance(Runner.class);

但这不能由 Guice 解决,因为 Runner<T, V>依赖于 GenericDAO<T, V> ,但您没有为它绑定(bind)一个确切的实现。因此,正如 jfpoilpret 所说,您必须在模块中为其绑定(bind)一些具体实现。

我猜您想确定确切的 GenericDAO<T, V>您传递给 Runner<T, V> 的实现基于一些输入数据,编译时不知道哪些数据的类型。现在,假设您有两个实现。

bind(new TypeLiteral<GenericDAO<String, ObjectID>>(){}).to(StringDAO.class);
bind(new TypeLiteral<GenericDAO<Double, ObjectID>>(){}).to(IntegerDAO.class);

根据不同类型的输入,你可以这样做

Injector injector = Guice.createInjector(new RunnerModule());

// possible input which you get from *somewhere* dynamically
Object object = 1.0;

TypeLiteral<?> matchedTypeLiteral = null;
for (Key<?> key : injector.getAllBindings().keySet()) {
  TypeLiteral<?> typeLiteral = key.getTypeLiteral();
  Type type = typeLiteral.getType();
  if (type instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType) type;
      if (parameterizedType.getRawType() == GenericDAO.class) {
        List<Type> actualTypeArguments =    Arrays.asList(parameterizedType.getActualTypeArguments());
        if (actualTypeArguments.get(0) == object.getClass())
          matchedTypeLiteral = typeLiteral;
    }
  }
};

Runner<?, ?> runner = new Runner<>((GenericDAO<?, ?>) injector.getInstance(Key.get(matchedTypeLiteral)));
System.out.println(runner.dao.getClass()); // IntegerDAO.class

如果Object object = "string"; ,然后将找到其他实现。这当然是相当丑陋的,可以通过检查子类和东西来改进,但我想你明白了。最重要的是,您无法解决这个问题。

如果你设法做到了(绕过它),请给我发一封电子邮件,因为我想知道这件事!不久前,我遇到了与您面临的相同问题。我写了一个简单的 BSON codec我想根据一些任意输入的类型加载通用接口(interface)的特定实现。这适用于 Java 到 BSON 的映射,但我无法以任何明智的方式反过来做,所以我选择了一个更简单的解决方案。

关于java - 使用 guice 将运行时参数传递给构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8147527/

相关文章:

c# - 从 ConfigureServices 中使用 ASP.NET Core DI 解析实例

c++ - C++的依赖注入(inject)框架

dependency-injection - Play Framework : Dependency Injection inside Action

java - 让 Java 应用程序在 Windows 上看起来是原生的 - 如何?

java - 在 JScrollPane 中获取正确的鼠标位置

java - 将与会者添加到 android 日历事件

c# - 让 autofac 与 mvc6 beta5 一起工作

java - 无法为@override方法抛出异常

java - 无法使用 Guice 和 Vertx 将同一实例注入(inject)多个 Verticles

java - 使用 JXL 关闭 Excel 中的网格线