4. Injeção de Dependências
A injeção de dependências pode ser considerada uma consequência da inversão de controlo. Iremos ilustrar isto com um novo exemplo. Considere a seguinte aplicação web de 3 camadas:
![]() |
Vamos assumir que o acesso à camada DAO é controlado pela interface [IArticlesDao] discutida anteriormente e que toda a aplicação é uma aplicação de compras baseada na Web. Os itens são aqueles geridos pela camada [Dao]. Assumimos que o acesso à camada de negócios é controlado pela seguinte interface:
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
Não nos deteremos no significado dos vários métodos. Limitar-nos-emos a observar que o método [getAllArticles], que se destina a recuperar a lista de todos os artigos à venda, necessita de acesso aos dados. Para o obter, deve chamar a interface [IArticlesDao]. O esqueleto de uma classe que implemente a interface [IArticlesDomain] poderá ter o seguinte aspeto:
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
Como mencionámos, certos métodos da interface da camada de negócios precisam de solicitar dados à camada [Dao]. A nossa classe de implementação [AchatsArticles] da interface [IArticlesDomain] necessita, portanto, de uma referência a uma implementação da interface [IArticlesDao]. Acima, o campo privado [_articlesDao] serve como essa referência. Esta referência é fornecida quando um objeto [AchatsArticles] é criado.
Suponhamos que a classe [ItemPurchases] já tenha sido escrita e que queiramos testá-la com um teste [Nunit]. Vamos criar este teste de forma a que utilize um ficheiro de configuração 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
Qual seria o conteúdo do ficheiro de configuração do Spring [spring-config-domain.xml]? Poderia ser o seguinte:
<?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>
Este ficheiro é o que já foi utilizado para instanciar o singleton [IArticlesDao] da camada [Dao], ao qual adicionámos o código para instanciar o singleton [IArticlesDomain] da camada de negócio. Como é que isto será construído?
- O código externo solicita uma referência ao singleton denominado «articlesdomain» ao Spring no ficheiro de configuração. É o que acontece com o método [init] da nossa classe de teste:
<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
- O Spring encontra a definição do singleton em questão no seu ficheiro de configuração. Ele descobre que, para o instanciar, precisa de outro singleton chamado "articlesdao":
<object name="articlesdomain" class="istia.st.articles.domain.AchatsArticles, articlesdomain">
<constructor-arg index="0">
<ref object="articlesdao" />
</constructor-arg>
</object>
- O Spring irá então instanciar o singleton "articlesdao". Já explicámos como isso é feito.
- Assim que isso estiver feito, pode instanciar o singleton "articlesdomain" e devolver uma referência ao mesmo ao código que o solicitou.
Este mecanismo pode ser representado graficamente da seguinte forma:
![]() |
Podemos ver que o Spring geriu a dependência que o singleton «articlesdomain» tinha em relação ao singleton «articlesdao». Para utilizar o Spring desta forma, tivemos de criar uma classe com um construtor que aceita o singleton dependente como argumento:
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
O termo «injeção de dependências» abrange ambos:
- a forma específica de construir as classes a instanciar com base nas suas dependências
- a forma como o Spring gere essas dependências ao instanciar essas classes

