Skip to content

3. 控制反转(IoC)

现在让我们重点探讨 Spring 用于配置应用程序的“控制反转”(IoC)概念。为阐明这一概念,让我们回到之前测试应用程序的架构:

为了从数据库管理系统(DBMS)中获取数据,测试类必须使用一个实现 [IArticlesDao] 接口的对象提供的服务,例如 [ArticlesDaoPlainODBC] 类型的对象。我们已经探讨了实例化此类对象的两种可能方案:

  • 在第一种方案中,测试类本身请求实例化一个 [ArticlesDaoPlainODBC] 类型的对象:
    <TestFixture()> _
    Public Class NunitTestArticlesDaoPlainOdbc

        ' the test object
        Private articlesDao As IArticlesDao

        <SetUp()> _
        Public Sub init()
            ' create an instance of the object to be tested
            articlesDao = New ArticlesDaoPlainODBC("odbc-firebird-articles", "SYSDBA", "masterkey")
        End Sub
...
    End Class

代码中存在对类名的硬编码依赖。如果实现 [IArticlesDao] 接口的类发生变更, [init] 方法中的代码也需要进行修改。对象之间存在以下关系:

[NunitTestArticlesDaoPlainOdbc] 类主动创建其所需的 [ArticlesDaoPlainODBC] 对象。回到“控制反转”这一术语,可以说正是该类“控制”着所需对象的创建。

  • 第二个解决方案采用了不同的方法。测试类现在变成了如下形式:
    <TestFixture()> _
    Public Class NunitSpringTestArticlesDaoPlainOdbc

        ' the test object
        Private articlesDao As IArticlesDao

        <SetUp()> _
        Public Sub init()
      ' retrieve an instance of the Spring object manufacturer
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-plainodbc.xml", FileMode.Open))
      ' request instantiation of the articles dao object
            articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
        End Sub
    ...
    End Class

该机制可概括如下:

在此,测试类并未主动请求创建 [ArticlesDaoPlainODBC] 对象,而是仅向 Spring 请求该对象的引用。若对象已存在,Spring 便返回其引用;若不存在,Spring 则会创建该对象。测试类已无法控制 [ArticlesDaoPlainODBC] 对象的创建过程,它仅需请求该对象的引用。 在此情况下,该请求将迫使 Spring 创建该对象。然而,在另一种情境下,可以设想所请求的对象已应应用程序的要求被创建。此时 Spring 不会重新创建该对象,而是返回对现有对象(单例)的引用。控制反转(IoC)的概念在此处的含义是:

  • 应用程序绝不会主动创建所需的单例,它仅请求这些单例的引用。
  • 由 Spring 决定在首次请求单例引用时创建该单例