4. Injection de dépendance
L'injection de dépendance peut être considérée comme une conséquence de l'inversion de contrôle. Nous allons l'illustrer sur un nouvel exemple. Considérons l'application web 3-tier suivante :
![]() |
On supposera que l'accès à la couche DAO est contrôlé par l'interface [IArticlesDao] étudiée précédemment et que l'ensemble de l'application est une application web d'achats d'articles sur le web. Les articles sont ceux gérés par la couche [Dao]. On suppose que l'accès à la couche métier est contrôlé par l'interface suivante :
Public Interface IArticlesDomain
' acheter un panier d'articles
Sub acheter(ByVal panier As Panier)
' obtenir la liste des articles
Function getAllArticles() As IList
' obtenir un article particulier
Function getArticleById(ByVal idArticle As Integer) As Article
' pour enregistrer les erreurs
ReadOnly Property erreurs() As ArrayList
End Interface
On ne s'attardera pas sur la signification des différentes méthodes. On notera simplement que la méthode [getAllArticles] qui doit obtenir la liste de tous les articles en vente, a besoin d'avoir accès aux données. Pour les obtenir, elle doit s'adresser à l'interface [IArticlesDao]. Le squelette d'une classe d'implémentation de l'interface [IArticlesDomain] pourrait ressembler à ceci :
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'champs privés
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' constructeur
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Nous l'avons dit, certaines méthodes de l'interface de la couche métier ont besoin de demander des données à la couche [Dao]. Notre classe d'implémentation [AchatsArticles] de l'interface [IArticlesDomain] a donc besoin d'une référence sur une implémentation de l'interface [IArticlesDao]. Ci-dessus, c'est le champ privé [_articlesDao] qui est cette référence. Celle-ci est fournie au moment de la construction d'un objet [AchatsArticles].
Supposons que la classe [AchatsArticles] ait été écrite et qu'on veuille la tester avec un test de type [Nunit]. Construisons celui-cii pour qu'il utilise un fichier de configuration Spring :
...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
<TestFixture()> _
Public Class NunitSpringTestArticlesDomain
' l'objet à tester
Private articlesDomain As IArticlesDomain
<SetUp()> _
Public Sub init()
' on récupère une instance du fabricant d'objets Spring
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' on demande l'instanciation de l'objet articles dao
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
...
End Class
Quel serait le contenu du fichier de configuration [spring-config-domain.xml] de Spring ? Il pourrait être le suivant :
<?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>
<!-- la classe d'implémentation de l'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>
<!-- la classe d'implémentation de l'interface IArticlesDomain -->
<object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
</objects>
Ce fichier est celui déjà utilisé pour instancier le singleton de type [IArticlesDao] de la couche [Dao] auquel on a ajouté le code pour instancier le singleton de type [IArticlesDomain] de la couche métier. Comment celui-ci sera-t-il construit ?
- un code externe demande à Spring une référence sur le singleton nommé " articlesdomain " dans le fichier de configuration. C'est le cas de la méthode [init] de notre classe de test :
<SetUp()> _
Public Sub init()
' on récupère une instance du fabricant d'objets Spring
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' on demande l'instanciation de l'objet articles dao
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
- Spring trouve dans son fichier de configuration, la définition du singleton en question. Il découvre que pour l'instancier, il a besoin d'un autre singleton appelé " articlesdao " :
<object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
- Spring va alors instancier le singleton "articlesdao". Nous avons déjà expliqué comment il le faisait.
- Ceci fait, il peut instancier le singleton "articlesdomain" et en rendre une référence au code qui l'a demandée.
Ce mécanisme pourrait être schématisé comme suit :
![]() |
On voit que Spring a géré la dépendance qu'avait le singleton "articlesdomain" vis à vis du singleton "articlesdao". Afin d'utiliser Spring de cette façon, il nous a fallu construire une classe avec un constructeur qui accepte comme argument le singleton dépendant :
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'champs privés
Private _articlesDao As IArticlesDao
' constructeur
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Le terme " injection de dépendance " recouvre à la fois :
- la façon particulière de construire les classes à instancier en fonction de leurs dépendances
- la façon qu'a Spring de gérer ces dépendances au moment de l'instanciation de ces classes

