一尘不染

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

java

我问了一个一般性的Spring问题:自动播发Spring Bean,并让多个人回答说ApplicationContext.getBean()应尽可能避免调用Spring 。这是为什么?

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

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

修正案

我接受下面的答案,但这是Martin Fowler的另一种选择,他讨论了依赖注入与使用Service Locator(本质上与调用wrapped相同ApplicationContext.getBean())的优点。

Fowler在某种程度上说:“ 使用服务定位器,应用程序类通过向定位器的消息显式地请求[服务]。使用注入时,没有显式请求,该服务将出现在应用程序类中-因此控制反转。控制反转是框架的常见功能,但要付出一定的代价,它往往难以理解,并且在尝试调试时会导致问题。因此,总的来说,我宁愿避免这种情况。除非我需要它。这并不是说这是一件坏事,只是我觉得需要通过更直接的替代自圆其说。 “


阅读 1807

收藏
2020-03-04

共1个答案

一尘不染

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

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

你想在任何地方说:

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>

Spring会自动注入myClassmyOtherClass

以这种方式声明所有内容,并且从根本上说是:

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

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

2020-03-04