I'm trying to inject things with Google Guice 2.0 and I have the following structure:
FooAction implements Action
BarAction implements Action
I then have an ActionLibrary with the following constructor:
ActionLibrary (List<Action> theActions)
When I request an instance of ActionLibrary from Guice, I would like Guice to identify both of the registered Action classes (FooAction, BarAction) and pass them into the constructor. The motivation here being that when I add a third action BazAction, it would be as simple as registering it in the Module and it would automatically be added to the list in the constructor.
Is this possible?
What you want for this is Multibindings. Specifically, you want to bind a Set<Action>
(not a List
, but a Set
is probably what you really want anyway) like this:
Multibinder<Action> actionBinder = Multibinder.newSetBinder(binder(), Action.class);
actionBinder.addBinding().to(FooAction.class);
actionBinder.addBinding().to(BarAction.class);
Then you can @Inject
the Set<Action>
anywhere.
Let me show you what I consider an even better way of multibinding things. If you want Action
s to be pluggable and let anyone add them, it's often useful to provide a simple Module
for someone to use that hides needing to instantiate the Multibinder
. Here's an example:
public abstract class ActionModule extends AbstractModule {
private Multibinder<Action> actionBinder;
@Override protected void configure() {
actionBinder = Multibinder.newSetBinder(binder(), Action.class);
configureActions();
}
/**
* Override this method to call {@link #bindAction}.
*/
protected abstract void configureActions();
protected final LinkedBindingBuilder<Action> bindAction() {
return actionBinder.addBinding();
}
}
Now why is this better? It allows someone to use an ActionModule
from anywhere to add more Action
s via the standard binding API. I think it's more readable. Here's an example usage:
public final class MyStandardActionModule extends ActionModule() {
@Override protected void configureActions() {
bindAction().to(FooAction.class);
bindAction().to(BarAction.class);
// If you need to instantiate an action through a Provider, do this.
bindAction().toProvider(BazActionProvider.class);
// You can also scope stuff:
bindAction().to(MySingletonAction.class).in(Singleton.class);
}
}
This pattern of using a Module
to hide the multibinder is used in Guice code. It's a little work up front, but keeps things clean. You can also do something similar for a MapBinder
if you need to. Keep in mind you can instantiate as many ActionModule
s as you want.
来源:https://stackoverflow.com/questions/4410712/injecting-collection-of-classes-with-guice