Skip to content

4. Dependency Injection

Dependency injection can be considered a consequence of inversion of control. We will illustrate this with a new example. Consider the following 3-tier web application:

We will assume that access to the DAO layer is controlled by the [IArticlesDao] interface discussed earlier and that the entire application is a web-based shopping application. The items are those managed by the [Dao] layer. We assume that access to the business layer is controlled by the following interface:

Public Interface IArticlesDomain
    ' buy a shopping cart of items
    Sub buy(ByVal basket As Basket)
    ' Get the list of items
    Function getAllArticles() As IList
    ' Get a specific item
    Function getArticleById(ByVal idArticle As Integer) As Article
    ' to record errors
    ReadOnly Property errors() As ArrayList
End Interface

We won't dwell on the meaning of the various methods. We will simply note that the [getAllArticles] method, which is supposed to retrieve the list of all items for sale, needs access to the data. To obtain it, it must call the [IArticlesDao] interface. The skeleton of a class implementing the [IArticlesDomain] interface might look like this:

Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
    Public Class PurchaseItems
        Implements IArticlesDomain

        'private fields
        Private _articlesDao As IArticlesDao
        Private _errors As ArrayList

        ' constructor
        Public Sub New(ByVal articlesDao As IArticlesDao)
            _articlesDao = articlesDao
        End Sub
...
    End Class
End Namespace

As we mentioned, certain methods of the business layer interface need to request data from the [Dao] layer. Our [AchatsArticles] implementation class of the [IArticlesDomain] interface therefore needs a reference to an implementation of the [IArticlesDao] interface. Above, the private field [_articlesDao] serves as this reference. This reference is provided when an [AchatsArticles] object is constructed.

Suppose the [ItemPurchases] class has been written and we want to test it with a [Nunit] test. Let’s build this test so that it uses a Spring configuration file:

...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
    <TestFixture()> _
    Public Class NunitSpringTestArticlesDomain

        ' the object under test
        Private articlesDomain As IArticlesDomain

        <SetUp()> _
        Public Sub init()
      ' Get an instance of the Spring object factory
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
      ' Request instantiation of the Articles DAO object
            articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
        End Sub
...
    End Class

What would be the content of Spring's configuration file [spring-config-domain.xml]? It could be as follows:

<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE objects PUBLIC "-//SPRING//DTD OBJECT//EN"
"http://www.springframework.net/dtd/spring-objects.dtd">

<objects>
    <description>Management of an articles table</description>

    <!-- the implementation class for the IArticlesDao interface -->
    <object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, articlesdao">
      <constructor-arg index="0">
            <value>odbc-firebird-articles</value>
        </constructor-arg>
         <constructor-arg index="1">
            <value>SYSDBA</value>
        </constructor-arg>
         <constructor-arg index="2">
            <value>masterkey</value>
        </constructor-arg>
    </object>

    <!-- the implementation class of the IArticlesDomain interface -->
  <object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
      <constructor-arg index="0">
        <ref object="articlesdao" />
    </constructor-arg>
  </object>
</objects>

This file is the one already used to instantiate the [IArticlesDao] singleton from the [Dao] layer, to which we have added the code to instantiate the [IArticlesDomain] singleton from the business layer. How will this be constructed?

  • External code requests a reference to the singleton named "articlesdomain" from Spring in the configuration file. This is the case with the [init] method of our test class:
        <SetUp()> _
        Public Sub init()
      ' We retrieve an instance of the Spring object factory
            Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
      ' we request the instantiation of the articles DAO object
            articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
        End Sub
  • Spring finds the definition of the singleton in question in its configuration file. It discovers that to instantiate it, it needs another singleton called "articlesdao":
  <object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
      <constructor-arg index="0">
        <ref object="articlesdao" />
    </constructor-arg>
  </object>
  • Spring will then instantiate the "articlesdao" singleton. We have already explained how it does this.
  • Once this is done, it can instantiate the "articlesdomain" singleton and return a reference to it to the code that requested it.

This mechanism could be diagrammed as follows:

We can see that Spring has managed the dependency that the "articlesdomain" singleton had on the "articlesdao" singleton. To use Spring in this way, we had to build a class with a constructor that accepts the dependent singleton as an argument:

Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
    Public Class ArticlePurchases
        Implements IArticlesDomain

        'private fields
        Private _articlesDao As IArticlesDao

        ' constructor
        Public Sub New(ByVal articlesDao As IArticlesDao)
            _articlesDao = articlesDao
        End Sub
...
    End Class
End Namespace

The term "dependency injection" encompasses both:

  • the specific way of constructing the classes to be instantiated based on their dependencies
  • the way Spring manages these dependencies when instantiating these classes