【问题标题】:Generalize guice's robot-legs example with Multibinding使用 Multibinding 泛化 guice 的机器人腿示例
【发布时间】:2011-10-01 08:02:57
【问题描述】:

我的这个用例与 Guice 的机器人腿示例非常相似,只是我不知道我有多少“腿”。因此我不能使用机器人腿示例所需的注释。

我希望在带有 Guice 的 Multibindings 扩展的 java.util.Set 中收集所有这些“腿”。

从技术上讲,在 PrivateModule 中,我希望将实现直接公开为将由 Multibindings 扩展提供的集合的一个元素。我只是不知道该怎么做。

有关参考和代码示例,请参阅此处的机器人腿示例:http://code.google.com/p/google-guice/wiki/FrequentlyAskedQuestions#How_do_I_build_two_similar_but_slightly_different_trees_of_objec


这是我的精确用例:

我有以下几点:

// Main application
public interface MyTree {...}
public interface MyInterface {
  public MyTree getMyTree() {}
}
public abstract class MyModule extends PrivateModule {}
public class MyManager {
  @Inject MyManager (Set<MyInterface> interfaces){ this.interfaces = interfaces }
}
public class MainModule extends AbstractModule {
  public void configure () {
    // Install all MyModules using java.util.ServiceLoader.
  }
}


// In expansion "square.jar"
public class SquareTree implements MyTree {...}
public class SquareImplementation implements MyInterface {
  @Inject SquareImplementation (MyTree tree) { this.tree = tree; }
  public MyTree getMyTree () { return this.tree; }
}
public class SquareModule extends MyModule { // correctly defined as a ServiceLoader's service.
  public void configure () {
    // How to make this public IN a multibinder's set?
    bind(MyInterface.class).to(SquareImplementation.class);

    // Implementation specific to the Squareimplementation.
    bind(MyTree.class).to(SquareTree.class);
  }
}

// In expansion "circle.jar"
public class CircleTree implements MyTree {...}
public class CircleImplementation implements MyInterface {
  @Inject CircleImplementation (MyTree tree) { this.tree = tree; }
  public MyTree getMyTree () { return this.tree; }
}
public class CircleModule extends MyModule { // correctly defined as a ServiceLoader's service.
  public void configure () {
    // How to make this public IN a multibinder's set?
    bind(MyInterface.class).to(CircleImplementation.class);

    // Implementation specific to the Circle implementation.
    bind(MyTree.class).to(CircleTree.class);
  }
}

由于我说的是扩展罐,我一开始并不认识它们,我什至不知道它们有多少:我需要用j.u.ServiceLoader和每个模块加载MyModules应该定义一个MyInterface 实现(这两部分都可以)。

问题是将所有MyInterface 实现放在一组中(在MyManager 中)。我该怎么做?


解决方案,完全基于 Jesse 的回答:

// Create the set binder.
Multibinder<MyInterface> interfaceBinder = Multibinder.newSetBinder(binder(), MyInterface.class, MyBinding.class);

// Load each module that is defined as a service.
for (final MyModule module : ServiceLoader.load(MyModule.class)) {

  // Generate a key with a unique random name, so it doesn't interfere with other bindings.
  final Key<MyInterface> myKey = Key.get(MyInterface.class, Names.named(UUID.randomUUID().toString()));
  install(new PrivateModule() {
    @Override protected void configure() {
      // Install the module as part of a PrivateModule so they have full hands on their own implementation.
      install(module);
      // Bind the unique named key to the binding of MyInterface.
      bind(myKey).to(MyInterface.class);
      // Expose the unique named binding
      expose(myKey);
    }
  });
  // bind the unique named binding to the set
  interfaceBinder.addBinding().to(myKey);
}

这允许我不强制“客户”扩展 PrivateModule,而是在 MyModule 是扩展 Module 的接口时使用任何模块实现。

【问题讨论】:

    标签: java guice multibinding robot-legs-problem


    【解决方案1】:

    看起来您需要跳过一些环节来促进来自私有模块的绑定,以便它们可以在顶级注入器的多重绑定中。

    这应该可行:

    public class SquareModule extends AbstractModule { // does not extend PrivateModule
      @Overide public void configure() {
        // this key is unique; each module needs its own!
        final Key<MyInterface> keyToExpose
            = Key.get(MyInterface.class, Names.named("square"));
    
        install(new PrivateModule() {
          @Override public void configure() {
    
            // Your private bindings go here, including the binding for MyInterface.
            // You can install other modules here as well!
            ...
    
            // expose the MyInterface binding with the unique key
            bind(keyToExpose).to(MyInterface.class);
            expose(keyToExpose);
          }
        });
    
        // add the exposed unique key to the multibinding
        Multibinder.newSetBinder(binder(), MyInterface.class).addBinding().to(keyToExpose);
      }
    }
    

    这种解决方法是必要的,因为多重绑定需要在顶级注入器中发生。但是该注入器看不到私有模块绑定,因此您需要公开它们。

    【讨论】:

    • 谢谢杰西,但是在阅读了你的回答后,我不确定我是否正确解释了这个问题。所以我用一个例子纠正了我的问题。现在这更容易理解了吗?
    • 好的,我会测试你的新答案并在这里报告结果。
    • 是的,它运行良好。让它模块化是相当困难的,但没关系。
    • 要使其可模块化,请创建您自己的 AbstractModule 子类,其中包含上述所有代码,以及一个抽象方法 configurePrivateBindings()。然后从匿名 PrivateModule 的 configure() 方法中调用该方法。要为每个实现获取唯一键,只需创建一个可以调用 toString() 的静态计数器。
    • 我为唯一键选择了“final”字段,但基本上,这完全一样。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多