这个解决方案会起作用,但我想向你提出一个稍微不同的解决方案。
具体来说,由于您将遍历一个深层对象结构,因此这实际上看起来像是Viser模式的工作。此外,你所描述的似乎调用了一个两阶段注入器:一个“bootstrap”阶段,可以注入透视创建的层次结构所需的内容(但不能注入任何透视创建的元素)和第二个阶段,它是你的应用程序使用的真正注入器(可以注入任何东西)。
我建议的是这个基本模式:让一个遍历层次结构的访问者,然后,它会注入那些需要它的东西,并记录那些需要注入其他地方的东西。然后,当它完成访问所有内容时,它用于制作一个新的,可以从原始内容和从透视创建的层次结构中注入内容。Injector.createChildInjectorInjectorInjector
首先定义一个可以访问此层次结构中所有内容的访问者:
public interface InjectionVisitor {
  void needsInjection(Object obj);
  <T> void makeInjectable(Key<T> key, T instance);
}
然后为所有透视创建的元素定义一个接口:
public interface InjectionVisitable {
  void acceptInjectionVisitor(InjectionVisitor visitor);
}
您将在透视创建的类中实现此接口,如下所示(假设类中的此代码):FooContainer
public void acceptInjectionVisitor(InjectionVisitor visitor) {
  visitor.needsInjection(this);
  visitor.makeInjectable(Key.get(FooContainer.class), this);
  for (InjectionVisitable child : children) {
    child.acceptInjectionVisitor(visitor);
  }
}
请注意,前两个语句是可选的 - 可能是透视层次结构中的某些对象不需要注入,也可能是其中一些对象以后不希望可注入。另外,请注意 - 的用法,这意味着如果您希望某些类可以与特定的注释一起注入,则可以执行如下操作:Key
visitor.makeInjectable(Key.get(Foo.class, Names.named(this.getName())), this);
现在,您如何实现?操作方法如下:InjectionVisitor
public class InjectionVisitorImpl implements InjectionVisitor {
  private static class BindRecord<T> {
    Key<T> key;
    T value;
  }
  private final List<BindRecord<?>> bindings = new ArrayList<BindRecord<?>>();
  private final Injector injector;
  public InjectionVisitorImpl(Injector injector) {
    this.injector = injector;
  }
  public void needsInjection(Object obj) {
    injector.injectMemebers(obj);
  }
  public <T> void makeInjectable(Key<T> key, T instance) {
    BindRecord<T> record = new BindRecord<T>();
    record.key = key;
    record.value = instance;
    bindings.add(record);
  }
  public Injector createFullInjector(final Module otherModules...) {
    return injector.createChildInjector(new AbstractModule() {
      protected void configure() {
        for (Module m : otherModules) { install(m); }
        for (BindRecord<?> record : bindings) { handleBinding(record); }
      }
      private <T> handleBinding(BindRecord<T> record) {
        bind(record.key).toInstance(record.value);
      }
    });
  }
}
然后,在方法中将其用作:main
PivotHierarchyTopElement top = ...; // whatever you need to do to make that
Injector firstStageInjector = Guice.createInjector(
   // here put all the modules needed to define bindings for stuff injected into the
   // pivot hierarchy.  However, don't put anything for stuff that needs pivot
   // created things injected into it.
);
InjectionVisitorImpl visitor = new InjectionVisitorImpl(firstStageInjector);
top.acceptInjectionVisitor(visitor);
Injector fullInjector = visitor.createFullInjector(
  // here put all your other modules, including stuff that needs pivot-created things
  // injected into it.
);
RealMainClass realMain = fullInjector.getInstance(RealMainClass.class);
realMain.doWhatever();
请注意,工作方式可确保,如果您将任何东西绑定到注入到透视层次结构中,您将获得由真实注入器注入的相同实例 - 只要能够处理注入,就会将注入委托给。createChildInjector@SingletonfullInjectorfirstStageInjectorfirstStageInjector
编辑以添加:一个有趣的扩展(如果你想深入研究深层的Guice魔法)是修改,以便它记录在你的源代码中调用.然后,当您的代码意外地告诉访问者绑定到同一键的两个不同内容时,您可以从Guice获得更好的错误消息。为此,您需要添加 to ,记录方法内部的结果,然后更改为:InjectionImplmakeInjectableStackTraceElementBindRecordnew RuntimeException().getStackTrace()[1]makeInjectablehandleBinding
private <T> handleBinding(BindRecord<T> record) {
  binder().withSource(record.stackTraceElem).bind(record.key).toInstance(record.value);
}