Consider injecting Provider<T> instances. Then you can choose the returned object graph by varying the "root" object that gets returned. Unused object graphs don't get created.
pseudo code:
// instance variable, you will probably want to maintain a collection of providers
@Inject @ReallyFast Provider<? extends SomeBaseType> reallyFastProvider;
public <T extends SomeBaseType> T getSomething(Request request) {
if (Type.REALLY_FAST.equals(request.getType())
return
reallyFastProvider.get();
else
// ...
}
Guice makes Provider<T> instances available for all its bindings, even if you didn't use bind(...).toProvider(...).
You can scope the providers (the original bindings) if you want to. It all depends on what you want to achieve.
If the object graphs are only slightly different (you can't vary "root" objects without some serious duplication), then you have what they call the "robot legs" problem.
Then you'll need the different injectors like you said.
Hope I'm making sense,
Robbie