使用Multibinding来概括guice的机器人腿示例

我有这个用例非常类似于Guice的机器人腿例子,除了我不知道我有多少“腿”。 因此,我无法使用机器人腿示例所需的注释。

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

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

有关参考和代码示例,请参阅此处的robot-legs示例: 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 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); } } 

因为我讲的是扩展jar,我起初并不知道它们,我甚至不知道它们中有多少存在:我需要使用juServiceLoader加载MyModule ,每个模块都应该定义一个MyInterface实现(这些两部分都可以)。

问题是将所有MyInterface实现放在一个集合中(在MyManager )。 我怎样才能做到这一点?


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

 // Create the set binder. Multibinder 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 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的接口。

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

这应该工作:

 public class SquareModule extends AbstractModule { // does not extend PrivateModule @Overide public void configure() { // this key is unique; each module needs its own! final Key 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); } } 

这种解决方法是必要的,因为多绑定需要在顶级注入器处进行。 但是私有模块绑定对于该注入器是不可见的,因此您需要公开它们。