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会在首次请求该单例引用时决定是否创建该单例


