4. Abhängigkeitsinjektion
Die Abhängigkeitsinjektion kann als eine Folge der Kontrollumkehr betrachtet werden. Wir werden dies anhand eines neuen Beispiels veranschaulichen. Betrachten wir die folgende 3-Tier-Webanwendung:
![]() |
Wir gehen davon aus, dass der Zugriff auf die Schicht DAO durch die zuvor behandelte Schnittstelle [IArticlesDao] gesteuert wird und dass es sich bei der gesamten Anwendung um eine Webanwendung für den Online-Kauf von Artikeln handelt. Die Artikel werden von der Schicht [Dao] verwaltet. Es wird angenommen, dass der Zugriff auf die Geschäftssschicht über die folgende Schnittstelle gesteuert wird:
Public Interface IArticlesDomain
' einen Warenkorb mit Artikeln kaufen
Sub acheter(ByVal panier As Panier)
' die Liste der Artikel abrufen
Function getAllArticles() As IList
' einen bestimmten Artikel abrufen
Function getArticleById(ByVal idArticle As Integer) As Article
' Fehler protokollieren
ReadOnly Property erreurs() As ArrayList
End Interface
Wir werden nicht näher auf die Bedeutung der verschiedenen Methoden eingehen. Es sei lediglich angemerkt, dass die Methode [getAllArticles], die die Liste aller zum Verkauf stehenden Artikel abrufen soll, Zugriff auf die Daten benötigt. Um diese zu erhalten, muss sie die Schnittstelle [IArticlesDao] aufrufen. Das Grundgerüst einer Klasse zur Implementierung der Schnittstelle [IArticlesDomain] könnte wie folgt aussehen:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'Private Felder
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' Konstruktor
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Wie bereits erwähnt, müssen bestimmte Methoden der Schnittstelle der Geschäftssschicht Daten von der Schicht [Dao] anfordern. Unsere Implementierungsklasse [AchatsArticles] der Schnittstelle [IArticlesDomain] benötigt daher eine Referenz auf eine Implementierung der Schnittstelle [IArticlesDao]. Im obigen Beispiel ist das private Feld [_articlesDao] diese Referenz. Diese wird beim Erstellen eines Objekts vom Typ [AchatsArticles] bereitgestellt.
Nehmen wir an, die Klasse [AchatsArticles] wurde geschrieben und wir möchten sie mit einem Test vom Typ [Nunit] testen. Erstellen wir diesen so, dass er eine Spring-Konfigurationsdatei verwendet:
...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
<TestFixture()> _
Public Class NunitSpringTestArticlesDomain
' das zu testende Objekt
Private articlesDomain As IArticlesDomain
<SetUp()> _
Public Sub init()
' Eine Instanz des Spring-Objektgenerators wird abgerufen
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' Es wird die Instanziierung des DAO-Objekts „articles“ angefordert
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
...
End Class
Was wäre der Inhalt der Spring-Konfigurationsdatei [spring-config-domain.xml]? Er könnte wie folgt lauten:
<?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>
<!-- die Implementierungsklasse der Schnittstelle 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>
<!-- die Implementierungsklasse der Schnittstelle IArticlesDomain -->
<object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
</objects>
Diese Datei ist dieselbe, die bereits zur Instanziierung des Singletons vom Typ [IArticlesDao] aus der Schicht [Dao] verwendet wurde, und der nun der Code zur Instanziierung des Singletons vom Typ [IArticlesDomain] aus der Geschäftsschicht hinzugefügt wurde. Wie wird dieser aufgebaut?
- Ein externer Code fordert von Spring eine Referenz auf das Singleton namens „articlesdomain“ in der Konfigurationsdatei an. Dies ist bei der Methode [init] unserer Testklasse der Fall:
<SetUp()> _
Public Sub init()
' Es wird eine Instanz des Spring-Objektgenerators abgerufen
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' die Instanziierung des DAO-Objekts „articles“ wird angefordert
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
- Spring findet in seiner Konfigurationsdatei die Definition des betreffenden Singletons. Es stellt fest, dass es zur Instanziierung ein weiteres Singleton namens „articlesdao“ benötigt:
<object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
- Spring instanziiert nun das Singleton „articlesdao“. Wie dies geschieht, haben wir bereits erläutert.
- Anschließend kann Spring das Singleton „articlesdomain“ instanziieren und eine Referenz darauf an den Code zurückgeben, der es angefordert hat.
Dieser Mechanismus lässt sich wie folgt schematisch darstellen:
![]() |
Man sieht, dass Spring die Abhängigkeit des Singletons „articlesdomain“ vom Singleton „articlesdao“ verwaltet hat. Um Spring auf diese Weise nutzen zu können, mussten wir eine Klasse mit einem Konstruktor erstellen, der das abhängige Singleton als Argument akzeptiert:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'private Felder
Private _articlesDao As IArticlesDao
' Konstruktor
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Der Begriff „Abhängigkeitsinjektion“ umfasst sowohl:
- die besondere Art und Weise, wie die zu instanziierenden Klassen entsprechend ihrer Abhängigkeiten aufgebaut werden
- die Art und Weise, wie Spring diese Abhängigkeiten zum Zeitpunkt der Instanziierung dieser Klassen verwaltet

