4. Iniezione di dipendenze
L'iniezione di dipendenze può essere considerata una conseguenza dell'inversione di controllo. Lo illustreremo con un nuovo esempio. Consideriamo la seguente applicazione web a 3 livelli:
![]() |
Supponiamo che l'accesso al livello DAO sia controllato dall'interfaccia [IArticlesDao] discussa in precedenza e che l'intera applicazione sia un'applicazione di shopping online. Gli articoli sono quelli gestiti dal livello [Dao]. Supponiamo che l'accesso al livello business sia controllato dalla seguente interfaccia:
Public Interface IArticlesDomain
Public Interface IArticlesDomain
' buy a basket of items
Sub acheter(ByVal panier As Panier)
' get the list of articles
Function getAllArticles() As IList
' get a specific item
Function getArticleById(ByVal idArticle As Integer) As Article
' to record errors
ReadOnly Property erreurs() As ArrayList
End Interface
Non ci soffermeremo sul significato dei vari metodi. Noteremo semplicemente che il metodo [getAllArticles], che dovrebbe recuperare l'elenco di tutti gli articoli in vendita, necessita di accedere ai dati. Per ottenerli, deve chiamare l'interfaccia [IArticlesDao]. Lo scheletro di una classe che implementa l'interfaccia [IArticlesDomain] potrebbe apparire così:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'private fields
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' manufacturer
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Come già accennato, alcuni metodi dell'interfaccia del livello business devono richiedere dati al livello [Dao]. La nostra classe di implementazione [AchatsArticles] dell'interfaccia [IArticlesDomain] necessita quindi di un riferimento a un'implementazione dell'interfaccia [IArticlesDao]. Nel codice sopra riportato, il campo privato [_articlesDao] funge da riferimento. Tale riferimento viene fornito al momento della creazione di un oggetto [AchatsArticles].
Supponiamo che la classe [ItemPurchases] sia stata scritta e che vogliamo testarla con un test [Nunit]. Creiamo questo test in modo che utilizzi un file di configurazione Spring:
...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
<TestFixture()> _
Public Class NunitSpringTestArticlesDomain
' the test object
Private articlesDomain As IArticlesDomain
<SetUp()> _
Public Sub init()
' retrieve an instance of the Spring object manufacturer
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
Quale sarebbe il contenuto del file di configurazione di Spring [spring-config-domain.xml]? Potrebbe essere il seguente:
<?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>
<!-- the IArticlesDao interface implementation class -->
<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 IArticlesDomain interface implementation class -->
<object id="articlesdomain" type="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
</objects>
Questo file è quello già utilizzato per istanziare il singleton [IArticlesDao] dal livello [Dao], al quale abbiamo aggiunto il codice per istanziare il singleton [IArticlesDomain] dal livello business. Come verrà costruito?
- Il codice esterno richiede a Spring, nel file di configurazione, un riferimento al singleton denominato "articlesdomain". È il caso del metodo [init] della nostra classe di test:
<SetUp()> _
Public Sub init()
' retrieve an instance of the Spring object manufacturer
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
- Spring trova la definizione del singleton in questione nel proprio file di configurazione. Scopre che per istanziarlo ha bisogno di un altro singleton chiamato "articlesdao":
<object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
- Spring istanzierà quindi il singleton "articlesdao". Abbiamo già spiegato come lo fa.
- Una volta fatto ciò, potrà istanziare il singleton "articlesdomain" e restituirne un riferimento al codice che lo ha richiesto.
Questo meccanismo potrebbe essere rappresentato graficamente come segue:
![]() |
Possiamo notare che Spring ha gestito la dipendenza che il singleton "articlesdomain" aveva dal singleton "articlesdao". Per utilizzare Spring in questo modo, abbiamo dovuto creare una classe con un costruttore che accetta il singleton dipendente come argomento:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'private fields
Private _articlesDao As IArticlesDao
' manufacturer
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Il termine "iniezione di dipendenze" comprende entrambi:
- il modo specifico in cui vengono costruite le classi da istanziare in base alle loro dipendenze
- il modo in cui Spring gestisce queste dipendenze durante l'istanziazione di tali classi

