2. Artigo 1 - Spring IoC
Objetivos do documento:
- explorar as possibilidades de configuração e integração do framework Spring (http://www.springframework.org)
- definir e utilizar o conceito de IoC (Inversão de Controle), também conhecido como injeção de dependência (Dependency Injection)
2.1. Configurar uma aplicação de três camadas com o Spring
Consideremos uma aplicação clássica de três camadas:
![]() |
Suponhamos que o acesso às camadas de negócios e DAO seja controlado por interfaces Java:
- a interface [IArticlesDao] para a camada de acesso aos dados
- a interface [IArticlesManager] para a camada de negócios
Na camada de acesso aos dados, ou camada DAO (Data Access Object), é comum trabalhar com um SGBD e, portanto, com um driver JDBC. Consideremos o esboço de uma classe que acessa uma tabela de artigos em um SGBD:
Para realizar uma operação no SGBD, qualquer método precisa de um objeto [Connection] que represente a conexão com o banco de dados, por meio da qual ocorrerão as trocas entre ele e o código Java. Para construir esse objeto, são necessárias quatro informações:
o nome da classe do driver JDBC do SGBD | |
a URL JDBC do banco de dados a ser utilizado | |
a identidade com a qual a conexão é estabelecida | |
a senha dessa identidade |
Como nossa classe [ArticlesDaoPlainJdbc] anterior pode obter essas informações? Existem várias possibilidades:
solução 1 — as informações estão codificadas diretamente na classe:
A desvantagem dessa solução é que é necessário modificar o código Java sempre que ocorrer uma alteração nessas informações, por exemplo, a mudança da senha.
Solução 2 — as informações são passadas para o objeto durante sua construção:
Aqui, o objeto recebe, no momento de sua construção, as informações necessárias para funcionar. O problema passa então para o código que transmitiu as quatro informações. Como ele as obteve? A seguinte classe [ArticlesManagerWithDataBase] da camada de negócios poderia construir um objeto [ArticlesDaoPlainJdbc] da camada de acesso aos dados:
![]() |
Vemos que, mais uma vez, as informações necessárias para a construção do objeto [ArticlesDaoPlainJdbc] são fornecidas ao construtor do objeto [ArticlesManagerWithDataBase]. Podemos imaginar que elas lhe são transmitidas por uma camada superior, como a camada de interface com o usuário. Chega-se assim, passo a passo, à camada mais alta do aplicativo. Devido à sua posição, essa camada não é chamada por uma camada que pudesse transmitir-lhe as informações de configuração de que necessita. Portanto, é preciso encontrar uma solução alternativa à configuração por construtor. A solução habitual para configurar uma aplicação em sua camada mais alta é o uso de um arquivo onde se encontram todas as informações suscetíveis de mudar ao longo do tempo. Pode haver vários arquivos desse tipo. Ao iniciar a aplicação, uma camada de inicialização criará, então, todos ou parte dos objetos necessários às diferentes camadas da aplicação.
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 [ArticlesDaoPlainJdbc] poderia ser o seguinte:
Uma aplicação é um conjunto de objetos que o Spring denomina de beans, pois eles seguem a norma JavaBean de nomenclatura dos acessadores e inicializadores (getters/setters) dos campos privados de um objeto. 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 analisado aqui, o acesso ao banco de dados de artigos será garantido por uma única instância da classe [ArticlesDaoPlainJdbc]. 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 [ArticlesDaoPlainJdbc] em um pacote chamado [istia.st.articles.dao]. As quatro informações necessárias para o construtor desse objeto são definidas dentro de uma tag <bean>...</bean>. Haverá tantas tags <bean> quanto singletons a serem construídos.
Em que momento ocorrerá a construção dos objetos definidos no arquivo do Spring? A inicialização de uma aplicação pode ser atribuída ao método main dessa mesma aplicação, caso ela possua um. Para uma aplicação web, pode ser o método [init] do servlet principal. Em toda aplicação, há um método que certamente será o primeiro a ser executado. Geralmente, é nesse método que ocorre a construção dos singletons.
Vejamos um exemplo. Suponhamos que queiramos testar a classe [ArticlesDaoPlainJdbc] mencionada anteriormente por meio de um teste JUnit. Uma classe de teste JUnit possui um método [setUp] executado antes de qualquer outro método. É nesse método que criaremos o singleton [ArticlesDaoPlainJdbc].
Se seguirmos a solução de passar as informações de configuração por meio do construtor, teremos a seguinte classe de teste:
A classe de chamada [TestArticlesPlainJdbc] precisa conhecer as quatro informações necessárias para a inicialização do singleton [ArticlesDaoPlainJdbc] a ser construído.
Se seguirmos a solução de passar as informações de configuração por meio de um arquivo de configuração, poderíamos ter a seguinte classe de teste utilizando o arquivo Spring descrito acima.
Aqui, a classe de chamada [TestSpringArticlesPlainJdbc] não precisa conhecer as informações necessárias para a inicialização do singleton a ser construído. Ela precisa apenas saber:
- [springArticlesPlainJdbc.xml]: o nome do arquivo de configuração do Spring descrito acima
- [articlesDao]: o nome do singleton a ser criado
Uma alteração no arquivo de configuração, fora dessas duas entidades, não tem nenhum impacto no código Java. Esse método de configuração dos objetos de uma aplicação é muito flexível. Para se configurar, a aplicação precisa saber apenas duas coisas:
- o nome do arquivo Spring que contém a definição dos singletons a serem criados
- os nomes desses singletons, que servem ao código Java para obter uma referência aos objetos aos quais foram associados por meio do arquivo de configuração
2.2. Injeção de dependências e inversão de controle
Vamos agora introduzir o conceito de injeção de dependência (Dependency Injection) utilizado pelo Spring para configurar as aplicações. Também se utiliza o termo inversão de controle (IoC, Inversion of Control). Consideremos a criação do singleton [ArticlesManagerWithDataBase] da camada de negócios da nossa aplicação:
![]() |
Para acessar os dados do SGBD, a camada de negócios deve utilizar os serviços de um objeto que implemente a interface [IArticlesDao], por exemplo, um objeto do tipo [ArticlesDaoPlainJdbc]. O código da classe [ArticlesManagerWithDataBase] poderia ser semelhante ao seguinte:
public class ArticlesManagerWithDataBase implements IArticlesManager {
// uma instância de acesso aos dados
private IArticlesDao articlesDao;
....
public ArticlesManagerWithDataBase (String driverClassName, String url, String user, String pwd, ...) {
...
// criação do serviço de acesso aos dados
articlesDao =(IArticlesDao)new ArticlesDaoPlainJdbc(driverClassName,url,user,pwd);
...
}
public ... doSomething(...){
...
}
}
A classe [ArticlesDaoPlainJdbc] deve, neste caso, implementar uma interface [IArticlesDao]:
Para criar o singleton do tipo [IArticlesDao] necessário para o funcionamento da classe, o construtor desta utiliza explicitamente o nome da classe de implementação da interface [IArticlesDao]:
Portanto, há uma dependência rígida no código em relação ao nome da classe. Se a classe de implementação da interface [IArticlesDao] vier a mudar, o código do construtor anterior precisaria ser alterado. Temos as seguintes relações entre os objetos:
![]() |
A classe [ArticlesManagerWithDataBase] toma por conta própria a iniciativa de criar o objeto [ArticlesDaoPlainJdbc] de que necessita. Voltando ao termo “inversão de controle”, pode-se dizer que é ela quem tem o “controle” para criar o objeto de que necessita.
Se tivéssemos que escrever uma classe de teste JUnit para a classe [ArticlesManagerWithDataBase], poderíamos ter algo como o seguinte:
A classe de teste cria uma instância da classe de negócios [ArticlesManagerWithDataBase], que, por sua vez, cria, em seu construtor, uma instância da classe de acesso a dados [ArticlesDaoPlainJdbc].
A solução com o Spring eliminará a necessidade de a classe de negócios [ArticlesManagerWithDataBase] conhecer o nome [ArticlesDaoPlainJdbc] da classe de acesso aos dados de que ela precisa. Isso permitirá alterá-la sem mexer no código Java da classe de negócios. O Spring permitirá criar simultaneamente os dois singletons: o da camada de acesso aos dados e o da camada de negócios. O arquivo de configuração do Spring definirá um novo bean:
A novidade está no bean que define o singleton da classe de negócios a ser criado:
<bean id="articlesManager" class="istia.st.articles.domain.ArticlesManagerWithDataBase">
<property name="articlesDao">
<ref bean="articlesDao"/>
</property>
</bean>
- a classe que implementa o bean [articlesManager] é definida: [ArticlesManagerWithDataBase]
- o campo [articlesDao] do bean recebe um valor por meio da tag <property name="articlesDao">. Trata-se do campo definido na classe [ArticlesManagerWithDataBase]:
Para que o campo [articlesDao] possa ser inicializado pelo Spring e sua tag <property>, é necessário que o campo siga a norma JavaBean e que exista um método [setArticlesDao] para inicializar o campo [articlesDao]. Observe-se que o nome do método é derivado de forma bem precisa do nome do campo. Paralelamente, geralmente existe um método [get...] para obter o valor do campo. Aqui, trata-se do método [getArticlesDao]. Nesta nova versão, a classe [ArticlesManagerWithDataBase] não possui mais um construtor. Ela não precisa mais dele.
- O valor que será atribuído ao campo [articlesDao] pelo Spring é o do bean [articlesDao] definido em seu arquivo de configuração:
<bean id="articlesManager" class="istia.st.articles.domain.ArticlesManagerWithDataBase">
<property name="articlesDao">
<ref bean="articlesDao"/>
</property>
</bean>
<bean id="articlesDao" class="istia.st.articles.dao.ArticlesDaoPlainJdbc">
<constructor-arg index="0">
.............
</bean>
- quando o Spring criar o singleton [ArticlesManagerWithDataBase], ele também criará o singleton [ArticlesDaoPlainJdbc]:
- O Spring criará um gráfico de dependências dos beans e verificará que o bean [articlesManager] depende do bean [articlesDao]
- ele criará o bean [articlesDao], ou seja, um objeto do tipo [ArticlesDaoPlainJdbc]
- em seguida, criará o bean [articlesManager] do tipo [ArticlesManagerWithDataBase]
Imaginemos agora um teste JUnit para a classe [ArticlesManagerWithDataBase]. Ele poderia ser semelhante ao seguinte:
Vamos acompanhar o processo de criação dos dois singletons definidos no arquivo Spring chamado [springArticlesManagerWithDataBase.xml].
- O método [setUp] acima solicita uma referência ao bean chamado [articlesManager]
- O Spring consulta seu arquivo de configuração e encontra o bean [articlesManager]. Se ele já estiver criado, o Spring simplesmente retorna uma referência ao objeto (singleton); caso contrário, ele o cria.
- O Spring identifica a dependência do bean [articlesManager] em relação ao bean [articlesDao]. Portanto, ele cria o singleton [articlesDao] do tipo [ArticlesDaoPlainJdbc], caso este ainda não tenha sido criado (singleton).
- Ele cria o singleton [articlesManager] do tipo [ArticlesManagerWithDataBase]
Esse mecanismo poderia ser esquematizado da seguinte forma:
![]() |
Recordemos a estrutura da classe [ArticlesManagerWithDataBase]:
Ao final da construção dos singletons pelo Spring, temos um objeto do tipo [ArticlesManagerWithDataBase] cujo campo [articlesDao] foi inicializado sem que ele saiba como. Diz-se que injetamos uma dependência no objeto [ArticlesManagerWithDataBase]. Diz-se também que houve inversão de controle: não é mais o objeto [ArticlesManagerWithDataBase] que toma a iniciativa de criar por conta própria o objeto que implementa a interface [IArticlesDao] de que necessita, mas sim a aplicação no nível mais alto (ao ser inicializada) que se encarrega de criar todos os objetos de que necessita, gerenciando as dependências entre eles.
A principal vantagem da configuração do singleton [ArticlesManagerWithDataBase] por meio de um arquivo Spring é que agora é possível alterar a classe de implementação correspondente ao campo [articlesDao] da classe [ArticlesManagerWithDataBase] sem que o código desta última seja modificado. Basta alterar o nome da classe na definição do bean [articlesDao] no arquivo Spring:
passará a ser, por exemplo:
O bean [ArticlesManagerWithDataBase] funcionará com essa nova classe de acesso a dados, sem nem mesmo perceber.
2.3. Spring IoC na prática
2.3.1. Exemplo 1
Consideremos a seguinte classe:
A classe possui:
- dois campos privados, nome e idade
- os métodos de leitura (get) e gravação (set) desses dois campos
- um método toString para recuperar o valor do objeto [Personne] na forma de uma sequência de caracteres
- um método `init`, que será chamado pelo Spring na criação do objeto, e um método `close`, que será chamado na destruição do objeto
Para criar objetos do tipo [Personne], utilizaremos o seguinte arquivo Spring:
Esse arquivo se chamará config.xml.
- Ele define dois beans com as chaves respectivas “pessoa1” e “pessoa2”, do tipo [Personne]
- Ele inicializa os campos [nom, age] de cada pessoa
- Ele define os métodos a serem chamados durante a construção inicial do objeto [init-method] e durante a destruição do objeto [destroy-method]
Para nossos testes, utilizaremos uma única classe de teste JUnit, à qual adicionaremos métodos sucessivamente. A primeira versão dessa classe será a seguinte:
Comentários:
- para obter os beans definidos no arquivo [config.xml], utilizamos um objeto do tipo [ListableBeanFactory]. Existem outros tipos de objetos que permitem acessar os beans. O objeto [ListableBeanFactory] é obtido no método [setUp] da classe de teste e armazenado em uma variável privada. Assim, ele estará disponível para todos os métodos de teste.
- O arquivo [config.xml] será colocado no [ClassPath] do aplicativo, c.a.d, em um dos diretórios explorados pela máquina virtual Java quando ela procura uma classe referenciada pelo aplicativo. O objeto [ClassPathResource] serve para procurar um recurso no [ClassPath] de um aplicativo, neste caso, o arquivo [config.xml].
- O Spring pode utilizar arquivos de configuração em diversos formatos. O objeto [XmlBeanFactory] permite analisar um arquivo de configuração no formato XML.
- A análise de um arquivo Spring resulta em um objeto do tipo [ListableBeanFactory], neste caso, o objeto bf. Com esse objeto, um bean identificado pela chave C é obtido por meio de bf.getBean(C).
- O método [test1] solicita e exibe o valor dos beans com as chaves “pessoa1” e “pessoa2”.
A estrutura do projeto Eclipse da nossa aplicação é a seguinte:

Comentários:
- a pasta [src] contém os códigos-fonte. Os códigos compilados serão colocados na pasta [bin], que não está representada aqui.
- O arquivo [config.xml] está na raiz da pasta [src]. A compilação do projeto o copia automaticamente para a pasta [bin], que faz parte da pasta [ClassPath] do aplicativo. É lá que ele é procurado pelo objeto [ClassPathResource].
- A pasta [lib] contém três bibliotecas Java necessárias para o aplicativo:
- commons-logging.jar e spring-core.jar para as classes Spring
- junit.jar para as classes JUnit
- a pasta [lib] também faz parte do [ClassPath] do aplicativo
A execução do método [test1] do teste JUnit produz os seguintes resultados:
Comentários:
- O Spring registra uma série de eventos por meio da biblioteca [commons-logging.jar]. Esses registros nos permitem compreender melhor o funcionamento do Spring.
- O arquivo [config.xml] foi carregado e, em seguida, processado
- a operação*
forçou a criação do bean [personne1]. Podemos ver o log do Spring a respeito disso. Como na definição do bean [personne1] havia sido escrito [init-method="init"], o método [init] do objeto [Personne] criado foi executado. A mensagem correspondente é exibida.
- A operação
fez com que o valor do objeto [Personne] criado fosse exibido.
- O mesmo fenômeno se repete para o bean-chave [personne2].
- A última operação
personne2 = (Personne) bf.getBean("personne2");
System.out.println("personne2=" + personne2.toString());
não resultou na criação de um novo objeto do tipo [Personne]. Se tivesse sido o caso, teríamos visto a exibição do método [init], o que não ocorre aqui. Esse é o princípio do singleton. Por padrão, o Spring cria apenas uma instância dos beans do seu arquivo de configuração. Trata-se de um serviço de referências a objetos. Se for solicitada a referência de um objeto ainda não criado, ele o cria e retorna uma referência. Se o objeto já tiver sido criado, o Spring se limita a fornecer uma referência.
- Pode-se observar que não há nenhum vestígio do método [close] do objeto [Personne], embora tenhamos escrito na definição dos beans [destroy-method=close]. É possível que esse método só seja executado quando a memória ocupada pelo objeto for recuperada pelo coletor de lixo (garbage collector). No momento em que isso ocorre, a aplicação já está encerrada e a exibição na tela não tem nenhum efeito. A ser verificado.
Agora que já dominamos os fundamentos de uma configuração do Spring, nossas explicações serão um pouco mais rápidas daqui em diante.
2.3.2. Exemplo 2
Consideremos a seguinte nova classe [Voiture]:
A classe apresenta:
- três campos privados: tipo, marca e proprietário. Esses campos podem ser inicializados e lidos por meio dos métodos públicos get e set dos beans. Eles também podem ser inicializados usando o construtor Carro(String, String, Pessoa). A classe possui ainda um construtor sem argumentos, a fim de seguir a norma JavaBean.
- um método toString para recuperar o valor do objeto [Voiture] na forma de uma cadeia de caracteres
- um método init que será chamado pelo Spring logo após a criação do objeto, e um método close que será chamado na destruição do objeto
Para criar objetos do tipo [Voiture], utilizaremos o seguinte arquivo Spring [config.xml]:
Este arquivo adiciona às definições anteriores um bean com a chave “voiture1” do tipo [Voiture]. Para inicializar esse bean, poderíamos ter escrito:
Em vez de escolher esse método já apresentado, optamos aqui por utilizar o construtor Carro(String, String, Pessoa) da classe. Além disso, o bean [voiture1] define o método a ser chamado durante a construção inicial do objeto [init-method] e aquele a ser chamado durante a destruição do objeto [destroy-method].
Para nossos testes, utilizaremos a classe de teste JUnit já apresentada, adicionando-lhe o seguinte método [test2]:
O método [test2] recupera o bean [voiture1] e o exibe.
A estrutura do projeto Eclipse permanece a mesma do teste anterior. A execução do método [test2] do teste JUnit produz os seguintes resultados:
Comentários:
- o método [test2] solicita uma referência ao bean [voiture1]
- linha 4: o Spring inicia a criação do bean [voiture1], pois esse bean ainda não foi criado (singleton)
- linha 6: como o bean [voiture1] faz referência ao bean [personne2], este último bean é, por sua vez, instanciado
- linha 7: o bean [personne2] foi criado. Seu método [init] é então executado.
- linha 9: o Spring indica que utilizará um construtor para criar o bean [voiture1]
- linha 10: o bean [voiture1] foi criado. Seu método [init] é então executado.
- linha 11: o método [test2] exibe o valor do bean [voiture1]
2.3.3. Exemplo 3
Introduzimos a seguinte nova classe [GroupePersonnes]:
Seus dois membros privados são:
membros: um array de pessoas que fazem parte do grupo
groupesDeTravail: um dicionário que atribui uma pessoa a um grupo de trabalho
Observe-se aqui que a classe [GroupePersonnes] não define um construtor sem argumentos para seguir a norma JavaBean. Vale lembrar que, na ausência de qualquer construtor, existe um construtor “padrão”, que é o construtor sem argumentos e que não realiza nenhuma ação.
O objetivo aqui é mostrar como o Spring permite inicializar objetos complexos, como aqueles que possuem campos do tipo matriz ou dicionário. Adicionamos um novo bean ao arquivo Spring [config.xml] anterior:
- A tag <list> permite inicializar um campo do tipo array ou que implemente a interface List com diferentes valores.
- A tag <map> permite fazer o mesmo com um campo que implemente a interface Map
Para nossos testes, utilizaremos a classe de teste JUnit já apresentada, adicionando-lhe o seguinte método [test3]:
O método [test3] recupera o bean [groupe1] e o exibe.
A estrutura do projeto Eclipse permanece a mesma do teste anterior. A execução do método [test3] do teste JUnit produz os seguintes resultados:
Comentários:
- o método [test3] solicita uma referência ao bean [groupe1]
- linha 4: o Spring inicia a criação desse bean
- como o bean [groupe1] faz referência aos beans [personne1] e [personne2], esses dois beans são criados (linhas 6 e 9) e seus métodos init são executados (linhas 7 e 10)
- linha 11: o bean [groupe1] foi criado. Seu método [init] é agora executado.
- linha 12: exibição solicitada pelo método [test3].
2.4. Spring para configurar aplicações web de três camadas
2.4.1. Arquitetura geral da aplicação
Deseja-se construir uma aplicação de três camadas com a seguinte estrutura:
![]() |
- as três camadas serão tornadas independentes por meio do uso de interfaces Java
- A integração das três camadas será realizada pelo Spring
- Serão criados pacotes separados para cada uma das três camadas, que serão denominados Control, Domain e Dao. Um pacote adicional conterá os aplicativos de teste.
A estrutura da aplicação no Eclipse poderia ser a seguinte:

2.4.2. A camada DAO de acesso aos dados
A camada DAO implementará a seguinte interface:
package istia.st.demo.dao;
public interface IDao1 {
public int doSometingInDaoLayer(int a, int b);
}
- Escreva duas classes, Dao1Impl1 e Dao1Impl2, que implementem a interface IDao1. O método Dao1Impl1. doSomethingInDaoLayer retornará a+b, e o método Dao1Impl2. doSomethingInDaoLayer retornará a-b.
- escrever uma classe de teste JUnit para testar as duas classes anteriores
2.4.3. A camada de negócios
A camada de negócios implementará a seguinte interface:
package istia.st.demo.domain;
public interface IDomain1 {
public int doSomethingInDomainLayer(int a, int b);
}
- Escreva duas classes, Domain1Impl1 e Domain1Impl2, que implementem a interface IDomain1. Essas classes terão um construtor que receba como parâmetro um objeto do tipo IDao1. O método Domain1Impl1.doSomethingInDomainLayer incrementará a e b em uma unidade e, em seguida, passará esses dois parâmetros para o método doSomethingInDaoLayer do objeto do tipo IDao1 recebido. Já o método Domain1Impl2.doSomethingInDomainLayer diminuirá a e b em uma unidade antes de fazer o mesmo.
- Escrever uma classe de teste JUnit para testar as duas classes anteriores
2.4.4. A camada de interface do usuário
A camada de interface do usuário implementará a seguinte interface:
package istia.st.demo.control;
public interface IControl1 {
public int doSometingInControlLayer(int a, int b);
}
- Escreva duas classes, Control1Impl1 e Control1Impl2, que implementem a interface IControl1. Essas classes terão um construtor que recebe um parâmetro do tipo IDomain1. O método Control1Impl1.doSomethingInControlLayer incrementará a e b em uma unidade e, em seguida, passará esses dois parâmetros para o método doSomethingInDomainLayer do objeto do tipo IDomain1 recebido. Já o método Control11Impl2.doSomethingInControlLayer diminuirá a e b em uma unidade antes de fazer o mesmo.
- Escrever uma classe de teste JUnit para testar as duas classes anteriores
2.4.5. Integração com o Spring
- Escrever um arquivo de configuração do Spring que determinará quais classes cada uma das três camadas anteriores deverá utilizar
- Escreva uma classe de teste JUnit utilizando diferentes configurações do Spring, a fim de destacar a flexibilidade da aplicação desenvolvida
- Escreva uma aplicação autônoma (método main) que passe dois parâmetros para a interface IControl1 e exiba o resultado gerado pela interface.
2.4.6. Uma solução
2.4.6.1. O projeto Eclipse

Os arquivos da pasta [lib] foram adicionados ao [ClassPath] do projeto.
2.4.6.2. O pacote [istia.st.demo.dao]
A interface:
Uma primeira classe de implementação:
Uma segunda classe de implementação:
2.4.6.3. O pacote [istia.st.demo.domain]
A interface:
Uma primeira classe de implementação:
Uma segunda classe de implementação:
2.4.6.4. O pacote [istia.st.demo.control]
A interface
Uma primeira classe de implementação:
Uma segunda classe de implementação:
2.4.6.5. Os arquivos de configuração [Spring]
Um primeiro [springMainTest1.xml]:
Um segundo [springMainTest2.xml]:
2.4.6.6. O pacote de testes [istia.st.demo.tests]
Um teste do tipo [main]:
Os resultados obtidos no console do Eclipse:
Outro teste utilizando o segundo arquivo de configuração [Spring]:
Resultados obtidos no console do Eclipse:
Por fim, um teste Junit:
2.5. Conclusion
O framework Spring oferece uma flexibilidade real tanto na arquitetura das aplicações quanto em sua configuração. Utilizamos o conceito IoC, um dos dois pilares do Spring. O outro pilar é o AOP (Programação Orientada a Aspectos), que não apresentamos. Ele permite adicionar, por meio de configuração, um “comportamento” a um método de classe sem alterar o código da mesma. Esquematicamente, o AOP permite filtrar as chamadas a determinados métodos:
![]() |
- o filtro pode ser executado antes ou depois do método M alvo, ou ambos.
- O método M ignora a existência desses filtros. Eles são definidos no arquivo de configuração do Spring.
- O código do método M não é alterado. Os filtros são classes Java a serem criadas. O Spring fornece filtros predefinidos, especialmente para gerenciar as transações do SGBD.
- Os filtros são beans e, como tal, são definidos no arquivo de configuração do Spring como beans.
Um filtro comum é o filtro transacional. Consideremos um método M da camada de negócios que realiza duas operações indissociáveis sobre dados (unidade de trabalho). Ele chama dois métodos, M1 e M2, da camada DAO para realizar essas duas operações.
![]() |
Por estar na camada de negócios, o método M abstrai-se do suporte desses dados. Ele não precisa, por exemplo, de partir do pressuposto de que os dados estão em um SGBD e que precisa colocar as duas chamadas aos métodos M1 e M2 dentro de uma transação de SGBD. Cabe à camada DAO cuidar desses detalhes. Uma solução para o problema anterior seria, então, criar um método na camada DAO que, por sua vez, chamasse os métodos M1 e M2, chamadas que ela incluiria em uma transação de SGBD.
![]() |
A solução de filtragem AOP é mais flexível. Ela permitirá definir um filtro que, antes da chamada de M, iniciará uma transação e, após a chamada, executará um commit ou rollback, conforme o caso.
![]() |
Essa abordagem apresenta várias vantagens:
- uma vez definido o filtro, ele pode ser aplicado a vários métodos, por exemplo, todos aqueles que necessitam de uma transação
- os métodos assim filtrados não precisam ser reescritos
- como os filtros a serem usados são definidos por configuração, é possível alterá-los
Além dos conceitos IoC e AOP, o Spring oferece diversas classes de suporte para aplicações de três camadas:
- para JDBC, SqlMap (iBatis), Hibernate, JDO (Java Data Object) na camada DAO
- para o modelo MVC na camada de interface do usuário
Para mais informações: http://www.springframework.org.









