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

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

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

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

具体来说,由于您要遍历深层的对象结构,因此这实际上看起来像是完成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 thatInjector 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中获得更好的错误消息。要做到这一点,你会希望将添加
StackTraceElement
BindRecord
,记录结果
newRuntimeException().getStackTrace()[1]
的方法内
makeInjectable
,然后更改
handleBinding
到:

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


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5507770.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-13
下一篇 2022-12-13

发表评论

登录后才能评论

评论列表(0条)

保存