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 tre livelli:
![]() |
Supponiamo che l’accesso al livello DAO sia controllato dall’interfaccia [IArticlesDao] esaminata in precedenza e che l’intera applicazione sia un’applicazione web per l’acquisto di articoli online. Gli articoli sono quelli gestiti dal livello [Dao]. Si suppone che l’accesso al livello business sia controllato dalla seguente interfaccia:
Public Interface IArticlesDomain
' si acquista un carrello di articoli
Sub acheter(ByVal panier As Panier)
' ottenere l'elenco degli articoli
Function getAllArticles() As IList
' ottenere un articolo specifico
Function getArticleById(ByVal idArticle As Integer) As Article
' per registrare gli errori
ReadOnly Property erreurs() As ArrayList
End Interface
Non ci soffermeremo sul significato dei diversi metodi. Si noti semplicemente che il metodo [getAllArticles], che deve ottenere l'elenco di tutti gli articoli in vendita, necessita di accedere ai dati. Per ottenerli, deve rivolgersi all'interfaccia [IArticlesDao]. Lo scheletro di una classe di implementazione dell’interfaccia [IArticlesDomain] potrebbe essere simile al seguente:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'campi privati
Private _articlesDao As IArticlesDao
Private _erreurs As ArrayList
' costruttore
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Come già detto, 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, tale riferimento è rappresentato dal campo privato [_articlesDao]. Esso viene fornito al momento della creazione di un oggetto [AchatsArticles].
Supponiamo che la classe [AchatsArticles] sia stata scritta e che si voglia testarla con un test di tipo [Nunit]. Creiamolo in modo che utilizzi un file di configurazione Spring:
...
Imports Spring.Objects.Factory.Xml
Imports System.IO
...
<TestFixture()> _
Public Class NunitSpringTestArticlesDomain
' l'oggetto da testare
Private articlesDomain As IArticlesDomain
<SetUp()> _
Public Sub init()
' si recupera un'istanza del generatore di oggetti Spring
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' viene richiesta l'istanziazione dell'oggetto articles dao
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
...
End Class
Quale sarebbe il contenuto del file di configurazione [spring-config-domain.xml] di Spring? 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>
<!-- la classe di implementazione dell'interfaccia 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 di implementazione dell'interfaccia IArticlesDomain -->
<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 di tipo [IArticlesDao] del livello [Dao], al quale è stato aggiunto il codice per istanziare il singleton di tipo [IArticlesDomain] del livello business. Come verrà costruito quest'ultimo?
- un codice esterno richiede a Spring un riferimento al singleton denominato "articlesdomain" nel file di configurazione. È il caso del metodo [init] della nostra classe di test:
<SetUp()> _
Public Sub init()
' si recupera un'istanza del generatore di oggetti Spring
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-domain.xml", FileMode.Open))
' si richiede l'istanziazione dell'oggetto DAO "articoli"
articlesDomain = CType(factory.GetObject("articlesdomain"), IArticlesDao)
End Sub
- Spring trova nel proprio file di configurazione la definizione del singleton in questione. 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 creerà quindi un'istanza del singleton "articlesdao". Abbiamo già spiegato come lo fa.
- Fatto ciò, può istanziare il singleton "articlesdomain" e restituirne un riferimento al codice che lo ha richiesto.
Questo meccanismo potrebbe essere schematizzato come segue:
![]() |
Si nota che Spring ha gestito la dipendenza del singleton "articlesdomain" dal singleton "articlesdao". Per utilizzare Spring in questo modo, abbiamo dovuto creare una classe con un costruttore che accetta come argomento il singleton dipendente:
Imports istia.st.articles.dao
...
Namespace istia.st.articles.domain
Public Class AchatsArticles
Implements IArticlesDomain
'campi privati
Private _articlesDao As IArticlesDao
' costruttore
Public Sub New(ByVal articlesDao As IArticlesDao)
_articlesDao = articlesDao
End Sub
...
End Class
End Namespace
Il termine "iniezione di dipendenze" comprende sia:
- il modo specifico in cui vengono costruite le classi da istanziare in base alle loro dipendenze
- il modo in cui Spring gestisce tali dipendenze al momento dell’istanziazione di queste classi

