gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-30 21:27:55 25 4
gpt4 key购买 nike

我有一个现有的对象层次结构,其中一些对象具有需要注入(inject)的字段。还有一些其他对象是使用 Google Guice 构造的并且需要注入(inject)对先前描述的对象层次结构中某些对象的引用。我如何使用 Guice 进行此类注入(inject)?

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

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

我目前将要采用的方法如下所述。

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

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

然后那些对象会像这样实现这个接口(interface):

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

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

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

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

最佳答案

此解决方案可行,但我想向您推荐一个略有不同的解决方案。

具体来说,由于您要遍历一个深层对象结构,这看起来确实像是访问者模式的工作。此外,您所描述的似乎需要一个双阶段注入(inject)器:一个“引导”阶段可以注入(inject)数据透视创建的层次结构所需的东西(但不能注入(inject)任何数据透视创建的元素)和第二阶段这是您的应用程序使用的真正注入(inject)器(可以注入(inject)任何东西)。

我建议的是这个基本模式:创建一个遍历层次结构的访问者,并且随着它的进行,它会注入(inject)那些需要它的东西,并记录那些需要在别处注入(inject)的东西。然后,当它完成访问所有内容时,它使用 Injector.createChildInjector 制作一个新的 Injector 可以从原始 Injector 注入(inject)东西和东西来自枢轴创建的层次结构。

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

public interface InjectionVisitor {
void needsInjection(Object obj);
<T> void makeInjectable(Key<T> key, T instance);
}

然后为所有 pivot 创建的元素定义一个接口(interface):

public interface InjectionVisitable {
void acceptInjectionVisitor(InjectionVisitor visitor);
}

您将在 pivot 创建的类中实现此接口(interface)(假设此代码在 FooContainer 类中):

public void acceptInjectionVisitor(InjectionVisitor visitor) {
visitor.needsInjection(this);
visitor.makeInjectable(Key.get(FooContainer.class), this);
for (InjectionVisitable child : children) {
child.acceptInjectionVisitor(visitor);
}
}

请注意,前两个语句是可选的 - 可能是枢轴层次结构中的某些对象不需要注入(inject),也可能是您以后不希望其中的一些对象可注入(inject)。另外,请注意 Key 的使用 - 这意味着如果您希望某些类可以使用特定注释注入(inject),您可以执行以下操作:

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 绑定(bind)在注入(inject)到数据透视层次结构中的东西,您将获得相同的实例注入(inject)通过您的真实注入(inject)器 - 只要 firstStageInjector 能够处理注入(inject),fullInjector 就会将注入(inject)委托(delegate)给 firstStageInjector

编辑添加:一个有趣的扩展(如果你想深入研究 Guice 魔法)是修改 InjectionImpl 以便它记录你的源代码中调用 makeInjectable 的地方。这样,当您的代码不小心告诉访问者有关绑定(bind)到同一键的两个不同事物时,您可以从 Guice 中获得更好的错误消息。为此,您需要将 StackTraceElement 添加到 BindRecord,记录 new RuntimeException().getStackTrace()[1] 的结果> 在方法 makeInjectable 中,然后将 handleBinding 更改为:

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

关于java - 如何使用 Guice @Inject 到现有对象层次结构中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2856004/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com