1

我们有一个基于 Spring 的大型应用程序,其中包括不同的模块以及自定义 API。虽然有些模块需要 Spring 上下文,因为它们只是包装了领域模型的一部分,但我们认为我们的一些 API 不需要。

例如,我们围绕 Jackson / Jersey 编写了一个包装器来提供和使用 REST 服务。有一个中央接口可以访问此 API。然而,实现需要另一个类和另一个类,依此类推。所以一个简单的初始化将是

A a = new A(new B(new C(), new D(new E())))

我们目前免于使用@Inject. 此 API 的上下文会扫描包,然后将其导入目标应用程序。

<import resource="classpath:api-context.xml" />

我们对此感到不舒服,并希望将 spring 上下文踢出 REST 包装器,这意味着我们希望 API 不需要,但不知道如何去做。它应该表示以下两种之一:

构造函数参数

在目标上下文中,这将需要创建几个 bean,每个 bean 都使用其依赖项进行初始化

<bean id="a" class="...A">
    <constructor-arg>
        <ref = b " />
    </constructor-arg>
</bean>

<bean id="b" class="...B">
    <constructor-arg>
        <ref = c " />
    </constructor-arg>
</bean>
<!-- And so on -->

Getter 和 Setter

或者,假设这AAInterfaceAInterface 的特定实现,我们可以说,A 默认使用 BInterface 的某个实现,依此类推,实际上在内部使用 new 设置它们:

public class A implements AInterface {
    private BInterface b = new B();
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}
// and so on

然后在我的目标上下文中,如果我想使用默认配置,我可以用一行初始化中央访问

<bean id="a" class="...A" />

或使用属性来设置它的 B。但是,如果我想在更远的地方更改一些东西,我必须初始化所有 bean 并设置属性。

如果我将 new 用于测试之外的服务,它对我来说似乎也不干净。


所以我们想知道其他 API 开发人员如何在不依赖上下文导入的情况下使他们的接口和 bean 可访问(顺便说一句,这也会用许多可能不需要的 bean 混淆目标上下文,例如,如果一个 API 提供了多个服务,而我只想要使用一个)?


编辑

不确定这是否更好:

public class A implements AInterface {
    private BInterface b
    public A() {
        b = new B();
    }
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}

或者

public class A implements AInterface {
    private BInterface b
    public A(B b) {
        this.b = b;
    }
}

从测试的角度来看,后者感觉最好,但它让我们回到了我上面描述的链,在我可以初始化 A 之前,我必须在我的上下文中初始化所有依赖的 bean。这感觉像太多的配置开销。

有人可能会争辩说,在使用类之前需要初始化所有依赖项是很正常的,我们应该重构我们的代码。然而,我们最终会得到很多实用程序/帮助程序类,它们也不是最好的设计,因为它们很难替换或测试。

4

2 回答 2

1

基本上,如果您的 API 不需要 Spring 上下文,则确实没有理由将其放在那里。

请注意您建议的第二种方法:

public class A implements AInterface {
    private BInterface b = new B();
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}

它有点问题,因为您在类中初始化接口,这将导致您的测试出现问题,因为您无法模拟这些对象。更好的解决方案是在使用它的类的构造函数中对其进行初始化。

于 2012-07-05T08:53:05.337 回答
0

只需将所有 bean 定义为默认延迟加载,然后您就不会实例化您不使用的服务。

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>

有关更多详细信息,请参阅http://static.springsource.org/spring/docs/2.0.x/reference/beans.html#beans-factory-lazy-init

于 2012-07-05T16:43:39.030 回答