使用多重绑定概括 guice 的机器人腿示例
我的用例与 Guice 的机器人腿示例非常相似,只是我不知道我有多少条“腿”。因此我无法使用机器人腿示例所需的注释。
我希望将所有这些“腿”收集到一个带有 Guice 的多绑定扩展的 java.util.Set 中。
从技术上讲,在 PrivateModule 中,我想直接将实现公开为将由多重绑定扩展提供的集合的元素。我只是不知道该怎么做。
有关参考和代码示例,请参阅此处的 robots-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<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);
}
}
因为我正在谈论扩展jars,我一开始不知道它们,我什至不知道它们有多少:我需要加载MyModule
与 juServiceLoader
并且每个模块应该定义一个 MyInterface
实现(这两部分都可以)。
问题是获取一组中的所有 MyInterface
实现(在 MyManager
中)。我怎样才能做到这一点?
解决方案,完全基于杰西的回答:
// 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 的接口)。
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.
I expect to gather all these "legs" in an java.util.Set with Guice's Multibindings extension.
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.
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
Here's my precise use-case:
I have the following:
// 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);
}
}
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 MyModule
s with j.u.ServiceLoader
and each module should define a MyInterface
implementation (these two parts are ok).
The issue is to get all the MyInterface
implementations in one set (in MyManager
). How can I do that?
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);
}
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看起来您需要跳过一些环节才能从私有模块中promite 绑定,以便它们可以位于顶级注入器的多重绑定中。
这应该可行:
此解决方法是必要的,因为多重绑定需要在顶级注入器上发生。但是私有模块绑定对该注入器不可见,因此您需要公开它们。
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.
This should work:
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.