2. Configurando uma aplicação com Spring
Consideremos uma aplicação clássica de três camadas:
![]() |
Suponhamos que o acesso à camada DAO seja controlado por uma interface [IArticlesDao]:
....
Namespace istia.st.articles.dao
Public Interface IArticlesDao
' lista de todos os artigos
Function getAllArticles() As IList
' adiciona um item
Function ajouteArticle(ByVal unArticle As Article) As Integer
' exclui um artigo
Function supprimeArticle(ByVal idArticle As Integer) As Integer
' altera um item
Function modifieArticle(ByVal unArticle As Article) As Integer
' pesquisa um artigo
Function getArticleById(ByVal idArticle As Integer) As Article
' exclui todos os itens
Sub clearAllArticles()
' insere itens em uma transação
Sub doInsertionsInTransaction(ByVal articles As Article())
' altera o estoque de um artigo
Function changerStockArticle(ByVal idArticle As Integer, ByVal mouvement As Integer) As Integer
End Interface
End Namespace
Na camada de acesso aos dados, ou camada DAO (Data Access Object), é comum trabalhar com um SGBD. Consideremos o caso em que se acessa esse objeto por meio de um driver ODBC. A estrutura básica de uma classe que acessa essa fonte ODBC poderia ser a seguinte:
NameSpace istia.st.articles.dao
Imports System.Data.Odbc
...
Public Class ArticlesDaoPlainODBC
Implements istia.st.articles.dao.IArticlesDao
' campos privados
Private connexion As OdbcConnection = Nothing
Private DSN As String
Public Sub New(ByVal DSN As String, ByVal user As String, ByVal passwd As String)
'recupera o nome da fonte ODBC
Me.DSN = DSN
' cria-se a cadeia de conexão
Dim connectString As String = String.Format("DSN={0};UID={1};PWD={2}", DSN, user, passwd)
'instanciar a conexão
connexion = New OdbcConnection(connectString)
End Sub
....
End Class
End NameSpace
Para realizar uma operação na fonte ODBC, qualquer método precisa de um objeto [OdbcConnection] que represente a conexão com o banco de dados, por meio da qual ocorrerão as trocas de dados entre ele e o aplicativo. Para criar esse objeto, são necessárias três informações:
o nome da fonte ODBC | |
a identidade sob a qual a conexão é criada | |
a senha associada a essa identidade |
Nossa classe [ArticlesDaoPlainODBC] obtém essas informações por meio do agente externo que instancia um membro da classe. Podemos nos perguntar como esse agente obtém as três informações necessárias para a instanciação da classe [ArticlesDaoPlainODBC]. Vejamos um exemplo. Suponhamos que queiramos escrever uma classe de teste da camada [Dao]. Teríamos a seguinte arquitetura:
![]() |
O esboço de uma classe de teste Nunit [http://www.nunit.org/] poderia ser o seguinte:
Imports System
Imports System.Collections
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports ArticlesDaoSqlmap = istia.st.articles.dao.ArticlesDaoSqlMap
Imports Article = istia.st.articles.domain.Article
Imports System.Threading
<TestFixture()> _
Public Class NunitTestArticlesDaoPlainOdbc
' o objeto a ser testado
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' cria-se uma instância do objeto a ser testado
articlesDao = New ArticlesDaoPlainODBC("odbc-firebird-articles", "SYSDBA", "masterkey")
End Sub
<Test()> _
Public Sub testGetAllArticles()
' verificação visual
listArticles()
End Sub
' listagem da tela
Private Sub listArticles()
Dim articles As IList = articlesDao.getAllArticles
For i As Integer = 0 To articles.Count - 1
Console.WriteLine(CType(articles(i), Article).ToString)
Next
End Sub
End Class
O ambiente de teste Nunit é uma adaptação para a plataforma .NET do ambiente JUnit, que existe para a plataforma Java. Na classe acima, o método com o atributo <SetUp()> é executado antes de cada método de teste. Já aquele com o atributo <TearDown()> é executado após cada teste. Não há nenhum no exemplo acima. Aqui, vemos que o método [init], que possui o atributo <SetUp()>, instancia um objeto [ArticlesDaoPlainODBC], passando diretamente as três informações de que o construtor desse objeto necessita.
Nossa classe de teste fica à mercê de uma alteração em qualquer uma das informações codificadas de forma “estática”. Seria preferível que essas informações fossem registradas em um arquivo de configuração, a fim de evitar recompilações desnecessárias quando elas mudarem. A solução habitual para configurar uma aplicação é o uso de um arquivo onde se encontram todas as informações suscetíveis de mudar ao longo do tempo. Existe uma grande variedade de arquivos de configuração. A tendência atual é utilizar arquivos XML. Essa é a opção adotada pelo Spring. O arquivo que configura um objeto [ArticlesDaoPlainODBC] 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>
<!-- a classe de implementação da interface IArticlesDao -->
<description>Gestion d'une table d'articles</description>
<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>
</objects>
O arquivo de configuração do Spring descreve os objetos a serem instanciados. Em geral, ele não especifica em que momento eles serão instanciados. O momento da instanciação é, portanto, determinado pelo código que utiliza esse arquivo. Os objetos descritos em um arquivo de configuração do Spring podem ser instanciados e inicializados de duas maneiras diferentes:
- indicando, como acima, os parâmetros a serem passados ao construtor do objeto
- fornecendo valores às propriedades do objeto (Property). Nesse caso, o objeto deve possuir um construtor padrão que o Spring utilizará para a instanciação.
Os objetos que, em uma aplicação, têm a função de prestar um serviço são frequentemente criados em uma única instância. Eles são chamados de singletons. Assim, em nosso exemplo de aplicação multicamadas apresentado no início deste documento, o acesso ao banco de dados de artigos será garantido por uma única instância da classe [ArticlesDaoPlainODBC]. Em uma aplicação web, esses objetos de serviço atendem a vários clientes ao mesmo tempo. Não se cria um objeto de serviço por cliente.
O arquivo de configuração do Spring acima permite criar um único objeto de serviço do tipo [ArticlesDaoPlainODBC] em um pacote chamado [istia.st.articles.dao]. As três informações necessárias para o construtor desse objeto são definidas dentro de uma tag <object>...</object>. Haverá tantas tags <object> quantos singletons precisarem ser construídos.
Vamos detalhar a configuração:
<objects> é a tag raiz de um arquivo de configuração do Spring. Ela indica a descrição dos objetos singleton a serem instanciados.
A tag <description> é opcional. Ela pode ser usada, por exemplo, para descrever a função do arquivo de configuração.
<object id="articlesdao" type="istia.st.articles.dao.ArticlesDaoPlainODBC, articlesdao">
...
</object>
A tag <object> serve para descrever um objeto a ser instanciado. Ela possui, neste caso, dois atributos:
- name: identificador do objeto. É por meio desse nome que o código externo fará referência ao objeto.
- class: no formato “nome da classe, nome do assembly”. A primeira informação é o nome completo da classe a ser instanciada. A segunda, o nome do DLL que contém essa classe. Em nosso exemplo, a classe está em um arquivo chamado [articlesdao.dll]
O conteúdo da tag <object> serve para descrever o modo de instanciação do objeto:
<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>
Vale lembrar a assinatura do fabricante da classe [ArticlesDaoPlainODBC]:
O objeto Spring [articlesdao] será instanciado pelo construtor acima com as três informações do arquivo de configuração: [odbc-firebird-articles, SYSDBA, masterkey].
Em que momento ocorrerá a criação dos objetos definidos no arquivo Spring? Em toda aplicação, há um método que certamente será o primeiro a ser executado. Geralmente, é nesse método que a criação dos singletons é solicitada. A inicialização de uma aplicação pode ser atribuída ao método main dessa mesma aplicação, caso ela possua um. Para a aplicação ASP.NET, pode ser o método [Application_Start] do arquivo [global.asax]. Para nossa classe de teste [Nunit], a inicialização do aplicativo ocorre no método associado ao atributo <Setup()>.
Como utilizar o arquivo de configuração acima em nossa classe [Nunit]? Veja um exemplo:
Imports System
Imports System.Collections
Imports NUnit.Framework
Imports istia.st.articles.dao
Imports ArticlesDaoSqlmap = istia.st.articles.dao.ArticlesDaoSqlMap
Imports Article = istia.st.articles.domain.Article
Imports System.Threading
Imports Spring.Objects.Factory.Xml
Imports System.IO
<TestFixture()> _
Public Class NunitSpringTestArticlesDaoPlainOdbc
' o objeto a ser testado
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
' obtém-se uma instância do criador de objetos do Spring
Dim factory As XmlObjectFactory = New XmlObjectFactory(New FileStream("spring-config-plainodbc.xml", FileMode.Open))
' solicita-se a instanciação do objeto DAO de artigos
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
End Sub
<Test()> _
Public Sub testGetAllArticles()
' verificação visual
listArticles()
End Sub
' listagem da tela
Private Sub listArticles()
Dim articles As IList = articlesDao.getAllArticles
For i As Integer = 0 To articles.Count - 1
Console.WriteLine(CType(articles(i), Article).ToString)
Next
End Sub
End Class
Comentários:
- para instanciar os objetos do arquivo de configuração do Spring, utiliza-se um objeto do tipo [XmlObjectFactory]. Trata-se de um objeto do tipo “Factory”, c.a.d, que serve para criar outros objetos (Factory = fábrica). O Spring dispõe de vários tipos de “Factory”, dependendo do arquivo de configuração utilizado. Neste caso, trata-se de um arquivo XML e, portanto, utiliza-se um tipo [XmlObjectFactory].
- De forma bastante lógica, um objeto do tipo [XmlObjectFactory] precisa do nome do arquivo de configuração XML, neste caso, [spring-config-plainodbc.xml]. Mais precisamente, o tipo [XmlObjectFactory] é instanciado com um fluxo de leitura criado a partir do arquivo XML, cujo nome é fornecido.
- Uma vez criado o objeto do tipo [XmlObjectFactory], obtém-se um objeto do arquivo de configuração por meio de [XmlObjectFactory].getObject("identificador"), em que "identificador" é o atributo [id] de um dos objetos do arquivo de configuração.
- Se o objeto solicitado ainda não tiver sido instanciado, o Spring o instancia usando as informações de seu arquivo de configuração e retorna uma referência a ele para o programa chamador. Se o objeto já tiver sido instanciado, o Spring simplesmente retorna a referência do objeto já existente. Esse é o princípio do singleton.
- Observe-se que a classe de teste [Nunit] não conhece o nome da classe de acesso aos dados. Esse nome está no arquivo de configuração. A classe de teste limita-se a solicitar um objeto que implemente a interface [IArticlesDao]:
' o objeto a ser testado
Private articlesDao As IArticlesDao
<SetUp()> _
Public Sub init()
...
articlesDao = CType(factory.GetObject("articlesdao"), IArticlesDao)
End Sub
É aí que reside todo o interesse do Spring. Se mudarmos a classe de implementação, nossa classe de teste não precisará ser alterada. Basta modificar o arquivo de configuração do Spring. A classe de teste, por sua vez, limita-se a trabalhar com uma interface e não com uma classe.
Vamos encerrar esta apresentação com alguns pontos práticos.
Quando escrevemos “O Spring vai instanciar...”, o que queremos dizer exatamente? Para a plataforma .NET, o Spring está contido em três arquivos:

Para um projeto .NET criado com o Visual Studio e que deva utilizar o Spring, proceder-se-á da seguinte forma:
- os três arquivos acima serão colocados na pasta [bin] do projeto
- O arquivo [Spring.Core.dll] deve fazer parte das referências do projeto:

- as classes que utilizam o Spring deverão importar determinados namespaces, entre os quais frequentemente o seguinte:
Outro ponto prático: onde se coloca o arquivo de configuração do Spring? Há vários locais possíveis. Um deles é a pasta [bin] do projeto. Foi lá que foi colocado o arquivo [spring-config-plainodbc.xml] do exemplo analisado.

