4. Afhankelijkheidsinjectie
Afhankelijkheidsinjectie kan worden beschouwd als een gevolg van omgekeerde controle. We zullen dit aan de hand van een nieuw voorbeeld illustreren. Laten we de volgende 3-tier-webapplicatie eens bekijken:
![]() |
We gaan ervan uit dat de toegang tot de laag DAO wordt geregeld door de eerder besproken interface [IArticlesDao] en dat de gehele applicatie een webapplicatie is voor het online kopen van artikelen. De artikelen worden beheerd door de laag [Dao]. We gaan ervan uit dat de toegang tot de bedrijfslaag wordt geregeld door de volgende interface:
Public Interface IArticlesDomain
' een winkelmandje met artikelen kopen
Sub acheter(ByVal panier As Panier)
' de lijst met artikelen ophalen
Function getAllArticles() As IList
' een specifiek artikel ophalen
Function getArticleById(ByVal idArticle As Integer) As Article
' om fouten vast te leggen
ReadOnly Property erreurs() As ArrayList
End Interface
We zullen niet verder ingaan op de betekenis van de verschillende methoden. We merken alleen op dat de methode [getAllArticles], die de lijst met alle te koop aangeboden artikelen moet ophalen, toegang tot de gegevens nodig heeft. Om deze te verkrijgen, moet deze methode een beroep doen op de interface [IArticlesDao]. Het raamwerk van een implementatieklasse van de interface [IArticlesDomain] zou er als volgt uit kunnen zien:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'privévelden
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' constructor
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Zoals gezegd moeten bepaalde methoden van de interface van de bedrijfslaag gegevens opvragen bij de laag [Dao]. Onze implementatieklasse [AchatsArticles] van de interface [IArticlesDomain] heeft daarom een verwijzing nodig naar een implementatie van de interface [IArticlesDao]. Hierboven is het privéveld [_articlesDao] deze verwijzing. Deze wordt verstrekt op het moment dat een object van het type [AchatsArticles] wordt aangemaakt.
Stel dat de klasse [AchatsArticles] is geschreven en dat we deze willen testen met een test van het type [Nunit]. Laten we deze zo aanmaken dat hij gebruikmaakt van een Spring-configuratiebestand:
...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
<TestFixture()> _
Public Class NunitSpringTestArticlesDomain
' het te testen object
Private articlesDomain As IArticlesDomain
<SetUp()> _
Public Sub init()
' we halen een instantie op van de Spring-objectfabrikant
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' er wordt gevraagd om het DAO-object ‘articles’ te instantiëren
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
...
End Class
Wat zou de inhoud zijn van het Spring-configuratiebestand [spring-config-domain.xml]? Het zou er als volgt uit kunnen zien:
<?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>Gestion d'une table d'articles</description>
<!-- de implementatieklasse van de interface IArticlesDao -->
<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>
<!-- de implementatieklasse van de interface IArticlesDomain -->
<object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
</objects>
Dit bestand is hetzelfde bestand dat al werd gebruikt om het singleton van het type [IArticlesDao] uit de laag [Dao] te instantiëren, waaraan de code is toegevoegd om het singleton van het type [IArticlesDomain] uit de bedrijfslaag te instantiëren. Hoe wordt dit opgebouwd?
- Externe code vraagt Spring om een verwijzing naar het singleton met de naam „articlesdomain“ in het configuratiebestand. Dit is het geval bij de methode [init] van onze testklasse:
<SetUp()> _
Public Sub init()
' we halen een instantie op van de Spring-objectgenerator
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' we vragen om het instantiëren van het DAO-object ‘artikelen’
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
- Spring vindt in zijn configuratiebestand de definitie van het betreffende singleton. Het ontdekt dat het, om er een instantie van te maken, een ander singleton nodig heeft met de naam "articlesdao":
<object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
- Spring zal vervolgens het singleton "articlesdao" instantiëren. We hebben al uitgelegd hoe het dat doet.
- Zodra dit is gebeurd, kan Spring het singleton "articlesdomain" instantiëren en een verwijzing hiernaar teruggeven aan de code die erom heeft gevraagd.
Dit mechanisme kan als volgt worden weergegeven:
![]() |
We zien dat Spring de afhankelijkheid van het singleton "articlesdomain" ten opzichte van het singleton "articlesdao" heeft afgehandeld. Om Spring op deze manier te kunnen gebruiken, moesten we een klasse bouwen met een constructor die het afhankelijke singleton als argument accepteert:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'privévelden
Private _articlesDao As IArticlesDao
' constructor
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
De term "afhankelijkheidsinjectie" omvat zowel:
- de specifieke manier waarop de te instantiëren klassen worden opgebouwd op basis van hun afhankelijkheden
- de manier waarop Spring deze afhankelijkheden beheert op het moment dat deze klassen worden geïnstantieerd

