如何在实现Spring IOC时避免使用ApplicationContext.getBean()

时间:2013-02-27 14:53:53

标签: java spring java-ee inversion-of-control spring-ioc

我刚刚开始使用Spring IOC概念。我经常看到互联网上发现的大多数例子都使用代码来获取对象。

ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) appContext.getBean("hello"); 

作为stackoverflow中这些问题12的参考。我推断,没有必要在代码中使用appContext.getBean(“hello”),这被认为是不好的做法。此外,不再推荐。在这里纠正我,如果我的推论是错误的。

保持这一点,我相应地改变了我的项目。 这是我的applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="utilClassRef" class="org.hd.derbyops.DUtils" lazy-init="false" />
<bean id="appContext" class="org.hd.derbyops.ContextProvider" lazy-init="false">
   <property name="utils" ref="utilClassRef" />
</bean>
</beans>

我的contextProvider类代码

public class ContextProvider implements ApplicationContextAware {

    private static ApplicationContext ctx;

    /**
     * Objects as properties
     */
    private static DUtils utils;

    public void setApplicationContext(ApplicationContext appContext)
            throws BeansException {
        ctx = appContext;

    }

    public static ApplicationContext getApplicationContext() {
        return ctx;
    }

    public static DUtils getUtils() {
        return utils;
    }

    public void setUtils(DUtils dUtilsRef) {
        utils = dUtilsRef;
    }

}

例如,考虑一个依赖于org.hd.derbyops.DUtils的A类。 我正在使用以下代码行

ContextProvider.getUtils();

为了在A类中获取DUtils对象,从而避免在我的代码中的任何地方使用ApplicationContext.getBean()

假设,如果我有10个类,并且我的类A依赖于所有类,那么在不使用ApplicationContext.getBean()的情况下创建和访问其对​​象。在这种情况下,如上所述,我想到了创建ContextProvider类的属性,然后是该属性的setter和getter,其中get<PropertyName>是静态的。所以,我可以在任何需要对象的地方使用它,比如这个

ContextProvider.get<PropertyName>;

这是我的简短问题。 首先,我的做法是对的吗?如果它是正确的,在启动时加载所有的bean,它不会成为性能杀手吗?如果不至少多次调用getBean,你会如何在应用程序中执行此操作?

如果您要设计一个网络应用程序&amp;您要实现Spring IOC,而不在任何代码中使用ApplicationContext.getBean()。你会怎么做?

注意:参考上面标记的其他问题

  

调用ApplicationContext.getBean()不是Inversion of Control!

2 个答案:

答案 0 :(得分:9)

简单的答案是肯定的,不,不,不。最后,在线搜索spring MVC,因为这可能就是你想要的。

所以,你的方法。是的,你已经完成了大部分工作。但是,对所有事物使用静态方法被认为是非常糟糕的做法。而且,你不需要。 Spring基于这样的想法:你可以简单地创建普通的pojos,spring会将它们用作单例,并将它们互相注入(它也可以动态创建对象,但我会选择常见的情况)。如果您使用静态类和方法,那么:

  • 您无法模拟它们进行单元测试(您正在使用JUnit吗?)
  • 您不能将它们与继承一起使用
  • 静态初始化程序是消除异常的好方法
  • 等等

所以,对于注射是肯定的,对静态的东西没有。

接下来,表现。你是对的,使用弹簧要慢很多,但是,如果你在启动时完成所有注射,它只会发生一次。 Spring适用于服务器端应用程序,其中可能存在许多传递数据的单例类。因此,可能有一个类可以从DB获取内容,一个用于处理它,一个用于显示它,而spring用于将它们连接在一起。

如果您在重复启动的应用程序中使用spring(如命令行应用程序),那么您将其用于错误的应用程序类型,并且您可能希望使用构建器或其他东西。 Spring适用于未经常重启的大型企业应用程序。

最后,如果您只是在启动时将一个类的所有依赖项注入其中,并且您对所有类执行此操作,那么您根本不需要执行任何getBean操作。此外,在bean上使用init-methoddestroy-method属性意味着一旦spring注入依赖项,就可以启动进程。你只需加载上下文,你的应用程序就会出现(双关语)。

对于Web项目,Spring MVC基本上采用控件模式的整体反转并将其应用于Web应用程序。弹出的东西由容器加载,你可以定义URL来响应使用bean名称。而且你的大部分代码都可以像pojos一样存在。如果你有一些非常复杂的东西,你可能想看一下春天的网络流程,但我建议你在尝试之前确保你的春天非常强大。

答案 1 :(得分:1)

以下是我在getBean()上实际调用ApplicationContext时获取第一个实例的示例。

public class Test{
  // Declare private static variable so that we can access it in main()
  private static Triangle triangle;

  // Use constructor injection to set the triangle
  public Test(Triangle triangle) {
      Test.triangle = triangle;
  }

  public static void main(String[] args) {
      // Specify the context file containing the bean definitions
      // Spring automatically creates instances of all the beans defined
      // in this XML file. This process is performed before you actually make
      // a getBean("beanName") call.
      ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

      // Use instance methods of triangle 
      Test.triangle.draw();
  }
} 

您可以使用其他方式:

spring.xml(您的bean配置XML文件)

<bean class="com.example.Test" init-method="myMethod">
    <constructor-args ref="triangle"/>
</bean>

现在为您的主要班级

public class Test {
  private final Triangle triangle;

  public Test (Triangle triangle) {
     this.triangle = triangle;
  }

  public static void main (String[] args) {
     ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
  }

  // Called by Spring immediately after the Triangle Bean has been created and
  // all the properties for the bean have been set. This method name must match
  // the one specified with destroy-method attribute in spring.xml
  public void myMethod () {
     triangle.draw();
  }
}