当前位置: 首页 > 面试题库 >

如何使用Guice @Inject到现有对象层次结构中?

郎同化
2023-03-14
问题内容

我有一个现有的对象层次结构,其中某些对象具有需要注入的字段。另外,还有一些其他对象是使用Google
Guice
构造的,需要注入对先前描述的对象层次结构中某些对象的引用。我该如何用Guice注射?

问题在于,现有层次结构中的对象不是使用Guice构造的,因此默认情况下不受注入过程的约束。当然,有injector.injectMembers()一种方法可以注入到现有的对象实例中,但是它不适用于对象层次结构。

对于那些想知道为什么我不能使用Guice构建提到的对象层次结构的人。此层次结构表示GUI对象,由GUI框架(Apache
Pivot
)根据声明性的GUI描述构建(实际上,此过程可以描述为对象反序列化)。这种方式的接口构造非常简单,我只想将某些服务引用注入接口对象,反之亦然(对于回调)。

下面介绍我当前要采用的方法。

为了注入到预先存在的对象层次结构中,只需让所有对注入感兴趣的对象实现某些接口,例如:

public interface Injectable {
  void injectAll(Injector injector);
}

然后,这些对象将实现此接口,如下所示:

public void injectAll(Injector injector) {
  injector.injectMembers(this);
  for (Injectable child : children)
    child.injectAll(injector);
}

然后,我只需要mainWindow.injectAll(injector)在层次结构中调用根对象,然后注入所有感兴趣的对象。

不是很好的解决方案,但是可以单方面完成工作。另一方面,我需要从该层次结构中注入对象。我想可以通过为此类对象实现自定义提供程序来完成。

我的问题有更好的解决方案吗?也许我的方法也有问题?


问题答案:

此解决方案可以使用,但我想向您提出一个稍微不同的解决方案。

具体来说,由于您要遍历深层的对象结构,因此这实际上看起来像是完成Visitor模式的工作。另外,您所描述的似乎需要两阶段注入器:“引导”阶段,可以注入枢轴创建的层次结构所需的内容(但不能注入任何枢轴创建的元素),第二阶段那是您的应用使用的真正的注入器(可以注入任何东西)。

我要提出的是这种基本模式:创建一个遍历层次结构的访问者,并且将它注入需要的那些东西,并记录那些需要注入到其他地方的东西。然后,当完成对所有内容的访问后,它将用于Injector.createChildInjector制作一个新文件Injector,该文件可以注入原始文件中的Injector内容,也可以注入数据透视表创建的层次结构中的内容。

首先定义一个可以访问此层次结构中所有内容的访问者:

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的作品可以确保如果你有任何@Singleton的注入枢轴层次的东西必然的事情,你会得到你真正的喷射阀喷射出相同的情况-在fullInjector将委托injectoion的firstStageInjector,只要firstStageInjector是能够处理注射。

编辑添加:对此的一个有趣扩展(如果您想深入研究Guice魔术)是进行修改,InjectionImpl以便将其记录在名为的源代码中makeInjectable。这样,当您的代码意外地告诉访问者有关同一键的两个不同内容时,这将使您从Guice中获得更好的错误消息。要做到这一点,你会希望将添加StackTraceElementBindRecord,记录结果new RuntimeException().getStackTrace()[1]的方法内makeInjectable,然后更改handleBinding到:

private <T> handleBinding(BindRecord<T> record) {
  binder().withSource(record.stackTraceElem).bind(record.key).toInstance(record.value);
}


 类似资料:
  • 零售商店的正确模式是什么?公司从商店销售产品。 这似乎违反了我对OOP所知的全部知识。通过层次结构向下传递数据的方法--在对象之间复制参数?我错过了什么?

  • 我想将Nightwatch的页面对象系统用于我们应用程序中使用的UI组件。因为nightwatch有自己的读取/初始化它们的方式,所以我看不到正确扩展/重用它们的方法。 例如,我想要一个“日期字段”的DateInputPageObject。它将识别标签、输入、日期选择器等。 我会在任何带有日期输入字段的页面上使用它。 我还想扩展页面对象。例如,。将为所有模态元素定义选择器-覆盖、容器、关闭按钮等。

  • 问题内容: 我在 .NET for WinRT(C#)中 ,我想将JSON字符串反序列化为,然后将字典值稍后转换为实际类型。JSON字符串可以包含对象层次结构,我也希望在其中包含子对象。 这是应该能够处理的示例JSON: 我尝试使用 DataContractJsonSerializer 这样做: 实际上,这对于第一个级别是可行的,但是 “父母” 只是一个不能强制转换为的对象: 然后,我尝试使用 J

  • 问题内容: 在“深度”对象层次结构中使用Builder模式的最佳实践是什么?详细地说,我探讨了将Joshua Bloch提出的Builder模式应用于我的XML绑定代码的想法(我使用的是SimpleXML,但是这个问题将适用于任何情况)。我的对象层次结构深达4个级别,具有不同程度的复杂性。我的意思是,在某些级别上,我的对象只有几个属性,而在其他级别上,我最多可以有10个属性。 因此,请考虑以下假设

  • 我正在试验Javers 3.5.1报告已提交更改的能力。似乎只有当更改是原语时才报告更改;当实体层次结构中的对象引用发生更改时,不会报告更改。 以下是一个示例: 上述代码片段的结果为0。 进一步的诊断表明,包含类中的对象引用有自己的id;函数只查看具有该id的包含类/实体,而不会向下遍历层次结构来定位其他引用和属性。当在InMemoryRepository中开始比较从历史记录到传递的globalI

  • D3 具有多种布局,用于严格树的有向图,如下所示: 我需要绘制一个不是树的节点层次结构,而是一个有向无环图。这是树布局的问题,因为几个分支收敛: 有人知道一般层次结构的D3布局吗?或者,对现有的treelayout进行一些巧妙的破解?我注意到GraphVis很好地处理了这种情况,但D3生成的图更适合这里的需求。