为什么Spring的AppplicationContext.getBean被认为是不好的?

2022-08-31 05:08:47

我问了一个一般性的Spring问题:自动浇注Spring Beans,并让多人回答说应该尽可能避免调用Spring'为什么?ApplicationContext.getBean()

我还应该如何访问我配置Spring创建的bean?

我在一个非Web应用程序中使用Spring,并计划访问LiorH所描述的共享对象。ApplicationContext

修正案

我接受下面的答案,但这是Martin Fowler的另一个观点,他讨论了依赖注入与使用服务定位器(本质上与调用包装器相同)的优点。ApplicationContext.getBean()

Fowler指出,“使用服务定位器,应用程序类通过向定位器发送消息显式请求它[服务]。使用注入时,没有显式请求,服务出现在应用程序类中 - 因此控制反转。控制反转是框架的一个共同特征,但这是有代价的。当您尝试调试时,它往往难以理解并导致问题。因此,总的来说,除非我需要它,否则我宁愿避免它(控制反转)。这并不是说这是一件坏事,只是我认为它需要证明自己在更直接的替代方案上。"


答案 1

我在对另一个问题的评论中提到了这一点,但是控制反转的整个想法是让你的类都不知道或关心他们如何获得他们所依赖的对象。这样,您可以随时轻松更改给定依赖项的实现类型。它还使类易于测试,因为您可以提供依赖项的模拟实现。最后,它使课程更简单,更专注于他们的核心责任。

呼叫不是控制反转!虽然更改为给定的bean名称配置的实现仍然很容易,但该类现在直接依赖于Spring来提供该依赖项,并且无法以任何其他方式获取它。你不能只是在测试类中制作自己的模拟实现,然后自己传递给它。这基本上违背了Spring作为依赖注入容器的目的。ApplicationContext.getBean()

无论你想说什么:

MyClass myClass = applicationContext.getBean("myClass");

例如,您应该声明一个方法:

public void setMyClass(MyClass myClass) {
   this.myClass = myClass;
}

然后在您的配置中:

<bean id="myClass" class="MyClass">...</bean>

<bean id="myOtherClass" class="MyOtherClass">
   <property name="myClass" ref="myClass"/>
</bean>

然后,弹簧将自动注入 .myClassmyOtherClass

以这种方式声明所有内容,并且在其根源上都有如下内容:

<bean id="myApplication" class="MyApplication">
   <property name="myCentralClass" ref="myCentralClass"/>
   <property name="myOtherCentralClass" ref="myOtherCentralClass"/>
</bean>

MyApplication是最核心的类,并且至少间接依赖于程序中的所有其他服务。在引导时,在您的方法中,您可以调用,但不需要在其他任何地方调用!mainapplicationContext.getBean("myApplication")getBean()


答案 2

选择服务定位器而不是控制反转 (IoC) 的原因是:

  1. 服务定位器对于其他人来说更容易在您的代码中遵循。IoC是“神奇的”,但维护程序员必须了解您错综复杂的Spring配置和所有无数的位置,才能弄清楚您如何连接对象。

  2. IoC对于调试配置问题来说很糟糕。在某些类别的应用程序中,应用程序在配置错误时不会启动,并且您可能没有机会逐步执行调试器所发生的情况。

  3. IoC主要是基于XML的(注释改进了事情,但仍然有很多XML)。这意味着开发人员无法处理您的程序,除非他们知道Spring定义的所有魔术标签。再了解Java是不够的。这阻碍了经验不足的程序员(即,当更简单的解决方案(如Service Locator)将满足相同的要求时,使用更复杂的解决方案实际上是糟糕的设计)。此外,对诊断 XML 问题的支持远远弱于对 Java 问题的支持。

  4. 依赖注入更适合大型程序。大多数时候,额外的复杂性是不值得的。

  5. 通常使用Spring来以防您“以后可能想要更改实现”。还有其他方法可以在没有Spring IoC复杂性的情况下实现这一目标。

  6. 对于Web应用程序(Java EE WAR),Spring上下文在编译时被有效地绑定(除非你希望操作员在爆炸的战争中围绕上下文进行咕噜咕噜)。你可以让Spring使用属性文件,但是使用servlets,属性文件需要位于预定的位置,这意味着你不能在同一个盒子上同时部署多个servlet。您可以在 Servlet 启动时使用 Spring 和 JNDI 来更改属性,但是如果您将 JNDI 用于管理员可修改的参数,那么对 Spring 本身的需求就会减少(因为 JNDI 实际上是一个服务定位器)。

  7. 使用Spring,如果Spring调度到您的方法,您可能会失去程序控制。这很方便,适用于许多类型的应用程序,但不是全部。当您需要在初始化期间创建任务(线程等)或需要可修改的资源时,您可能需要控制程序流,而Spring在内容绑定到WAR时并不知道这些资源。

Spring非常适合交易管理,并具有一些优势。只是IoC在许多情况下可能会过度工程化,并为维护者带来不必要的复杂性。不要自动使用IoC而不考虑不首先使用它的方法。


推荐