使用Multibinding来概括guice的机器人腿示例 [英] Generalize guice's robot-legs example with Multibinding

查看:192
本文介绍了使用Multibinding来概括guice的机器人腿示例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have this use case that is very similar to the robot-legs example of Guice, except I don't know how many "legs" I have. Therefore I can't use the annotations needed for the robot-legs example.

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

I expect to gather all these "legs" in an java.util.Set with Guice's Multibindings extension.

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

Technically, in a PrivateModule I would like to expose an implementation directly as an element of the set that will be provided by the Multibindings extension. I just don't know how to do that.

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

For reference and code example, see the robot-legs example here: 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);
  }
}

由于我在谈论扩展罐,我不喜欢一开始我不知道它们,我甚至不知道它们中有多少存在:我需要用 juServiceLoader <加载 MyModule / code>并且每个模块应该定义一个 MyInterface 实现(这两部分都可以)。

Since I'm speaking about expansion jars, I don't know them at first, I don't even know how many of them there exist: I need to load the MyModules with j.u.ServiceLoader and each module should define a MyInterface implementation (these two parts are ok).

问题是在一组中获得所有 MyInterface 实现(在 MyManager 中)。我怎么能这样做?

The issue is to get all the MyInterface implementations in one set (in MyManager). How can I do that?

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

Solution, completely based upon Jesse's answer :

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

这允许我不强迫客户扩展私有模块,但是如果MyModule是扩展Module的接口,则使用任何模块实现。

This allows me to not force the "customer" to extend a PrivateModule, but rather use any module implementation if MyModule is an interface that extends Module.

推荐答案

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

It looks like you're going to need to jump through some hoops to promite bindings from the private module so that they can be in the top-level injector's multibinding.

这应该有效:

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

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

This workaround is necessary because multibindings need to happen at the top-level injector. But private module bindings aren't visible to that injector, so you need to expose them.

这篇关于使用Multibinding来概括guice的机器人腿示例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆