我问了一个常见的Spring问题:自动转换Spring bean,很多人回答说应该尽可能避免调用Spring的ApplicationContext.getBean()。为什么呢?

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

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

修正案

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

In part, Fowler states, "With service locator the application class asks for it [the service] explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control. Inversion of control is a common feature of frameworks, but it's something that comes at a price. It tends to be hard to understand and leads to problems when you are trying to debug. So on the whole I prefer to avoid it [Inversion of Control] unless I need it. This isn't to say it's a bad thing, just that I think it needs to justify itself over the more straightforward alternative."


当前回答

其思想是依赖于依赖注入(控制反转,IoC)。也就是说,您的组件已经配置了所需的组件。这些依赖关系是注入的(通过构造函数或设置函数)——你不能自己得到。

getbean()要求您在组件中显式地命名bean。相反,通过使用IoC,您的配置可以确定将使用什么组件。

这让你可以轻松地用不同的组件实现重新连接应用程序,或者通过提供模拟变量(例如,模拟DAO,这样你就不会在测试期间碰到数据库)以一种直接的方式配置测试对象。

其他回答

我只发现了两种需要getBean()的情况:

其他人已经提到在main()中使用getBean()为独立程序获取“主”bean。

我使用getBean()的另一种情况是交互用户配置为特定情况确定bean组成。因此,例如,引导系统的一部分使用带scope='prototype' bean定义的getBean()循环遍历数据库表,然后设置其他属性。据推测,有一种调整数据库表的UI比试图(重新)编写应用程序上下文XML更友好。

其思想是依赖于依赖注入(控制反转,IoC)。也就是说,您的组件已经配置了所需的组件。这些依赖关系是注入的(通过构造函数或设置函数)——你不能自己得到。

getbean()要求您在组件中显式地命名bean。相反,通过使用IoC,您的配置可以确定将使用什么组件。

这让你可以轻松地用不同的组件实现重新连接应用程序,或者通过提供模拟变量(例如,模拟DAO,这样你就不会在测试期间碰到数据库)以一种直接的方式配置测试对象。

其他人指出了普遍的问题(并且是有效的答案),但我只想提供一个额外的评论:并不是说你永远不应该这样做,而是尽可能少地做。

通常这意味着它只执行一次:在引导期间。然后,它只是访问“根”bean,通过它可以解决其他依赖关系。这可以是可重用的代码,如基本servlet(如果开发web应用程序)。

Spring的前提之一是避免耦合。定义和使用接口,DI, AOP,避免使用ApplicationContext.getBean():-)

的确,在application-context.xml中包含该类可以避免使用getBean。然而,即使这样,实际上也是不必要的。如果你正在编写一个独立的应用程序,并且你不想在application-context.xml中包含你的驱动程序类,你可以使用下面的代码让Spring自动装配驱动程序的依赖项:

public class AutowireThisDriver {

    private MySpringBean mySpringBean;    

    public static void main(String[] args) {
       AutowireThisDriver atd = new AutowireThisDriver(); //get instance

       ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                  "/WEB-INF/applicationContext.xml"); //get Spring context 

       //the magic: auto-wire the instance with all its dependencies:
       ctx.getAutowireCapableBeanFactory().autowireBeanProperties(atd,
                  AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);        

       // code that uses mySpringBean ...
       mySpringBean.doStuff() // no need to instantiate - thanks to Spring
    }

    public void setMySpringBean(MySpringBean bean) {
       this.mySpringBean = bean;    
    }
}

当我有一些独立的类需要使用我的应用程序的某些方面(例如测试)时,我需要这样做几次,但我不想将它包含在应用程序上下文中,因为它实际上不是应用程序的一部分。还请注意,这避免了使用字符串名称查找bean的需要,我一直认为这是丑陋的。