Skip to content

3. 控制反转 IoC

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

为了访问 SGBD 的数据,测试类必须使用实现 [IArticlesDao] 接口的对象提供的服务,例如 [ArticlesDaoPlainODBC] 类型的对象。我们探讨了实例化此类对象的两种可能方案:

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

         ' 待测对象
        Private articlesDao As IArticlesDao

        <SetUp()> _
        Public Sub init()
             ' 创建待测对象的实例
            articlesDao = New ArticlesDaoPlainODBC("odbc-firebird-articles", "SYSDBA", "masterkey")
        End Sub
...
    End Class

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

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

  • 第二种方案的做法则有所不同。测试类已变为如下形式:
    <TestFixture()> _
    Public Class NunitSpringTestArticlesDaoPlainOdbc

         ' 待测对象
        Private articlesDao As IArticlesDao

        <SetUp()> _
        Public Sub init()
       ' 获取 Spring 对象生成器的实例
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-plainodbc.xml", FileMode.Open))
       ' 请求实例化 articles dao 对象
            articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
        End Sub
    ...
    End Class

该机制可概括如下:

在此,测试类并未主动请求创建 [ArticlesDaoPlainODBC] 对象。它仅向 Spring 请求该对象的引用。如果对象存在,Spring 便返回其引用;如果不存在,则会创建该对象。 测试类已不再控制 [ArticlesDaoPlainODBC] 对象的创建。它仅请求该对象的引用。在此情况下,该请求将迫使 Spring 创建该对象。但在其他场景中,可以设想被请求的对象已由应用程序提前创建。 此时 Spring 不会重新创建该对象,而是返回对已存在对象(单例)的引用。控制反转(IoC)的概念在此处的含义是:

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