2. Artigo 1 - Spring IoC
Objetivos deste 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 Controlo), também conhecido como Injeção de Dependências
2.1. Configurar uma aplicação de 3 camadas com o Spring
Considere uma aplicação clássica de 3 camadas:
![]() |
Vamos assumir que o acesso às camadas de negócios e DAO é 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 a dados, ou camada DAO (Data Access Object), é comum trabalhar com um SGBD e, portanto, com um controlador JDBC. Considere o esqueleto de uma classe que acede a uma tabela de artigos num SGBD:
Para realizar uma operação no SGBD, cada método requer um objeto [Connection] que representa a ligação à base de dados, através da qual os dados serão trocados entre a base de dados e o código Java. Para criar este objeto, são necessárias quatro informações:
o nome da classe do controlador JDBC do SGBD | |
o URL JDBC da base de dados a utilizar | |
as credenciais utilizadas para estabelecer a ligação | |
A palavra-passe para este nome de utilizador |
Como é que a nossa classe [ArticlesDaoPlainJdbc] anterior pode obter esta informação? Existem várias possibilidades:
Solução 1 - a informação está codificada na classe:
A desvantagem desta solução é que é necessário modificar o código Java sempre que alguma destas informações for alterada, como por exemplo, quando a palavra-passe for alterada.
Solução 2 — a informação é passada para o objeto durante a sua construção:
Aqui, o objeto recebe as informações necessárias para funcionar no momento em que é criado. O problema passa então para o código que lhe forneceu essas quatro informações. Como é que as obteve? A seguinte classe [ArticlesManagerWithDataBase], na camada de negócios, poderia criar um objeto [ArticlesDaoPlainJdbc] a partir da camada de acesso aos dados:
![]() |
Podemos ver que, mais uma vez, a informação necessária para construir o objeto [ArticlesDaoPlainJdbc] é fornecida ao construtor do objeto [ArticlesManagerWithDataBase]. Podemos imaginar que esta informação lhe é passada por uma camada superior, como a camada da interface do utilizador. Chegamos assim gradualmente à camada mais alta da aplicação. Devido à sua posição, esta camada não é chamada por uma camada que lhe possa passar as informações de configuração de que necessita. Temos, portanto, de encontrar uma alternativa à configuração baseada no construtor. A abordagem padrão para configurar uma aplicação na sua camada mais elevada consiste em utilizar um ficheiro que contenha todas as informações suscetíveis de alteração ao longo do tempo. Poderá haver vários ficheiros deste tipo. Aquando do arranque da aplicação, uma camada de inicialização criará então a totalidade ou parte dos objetos necessários às várias camadas da aplicação.
Existe uma grande variedade de ficheiros de configuração. A tendência atual é utilizar ficheiros XML. Esta é a abordagem adotada pelo Spring. O ficheiro que configura um objeto [ArticlesDaoPlainJdbc] pode ter o seguinte aspeto:
Uma aplicação é um conjunto de objetos que o Spring denomina beans, porque seguem o padrão JavaBean para nomear acessadores e inicializadores (getters/setters) dos campos privados de um objeto. Os objetos numa aplicação que servem um propósito específico são frequentemente criados como uma única instância. Estes são chamados de singletons. Assim, no nosso exemplo de aplicação multicamadas aqui discutido, o acesso à base de dados de artigos será tratado por uma única instância da classe [ArticlesDaoPlainJdbc]. Para uma aplicação web, estes objetos de serviço atendem a vários clientes ao mesmo tempo. Não é criado um objeto de serviço para cada cliente.
O ficheiro de configuração Spring acima permite a criação de um único objeto de serviço do tipo [ArticlesDaoPlainJdbc] num pacote denominado [istia.st.articles.dao]. As quatro informações exigidas pelo construtor deste objeto são definidas dentro de uma tag <bean>...</bean>. Haverá tantas tags <bean> quantos os singletons a serem criados.
Quando é que os objetos definidos no ficheiro Spring serão criados? A inicialização da aplicação pode ser tratada pelo método main da aplicação, caso esta o possua. No caso de uma aplicação web, este pode ser o método [init] do servlet principal. Todas as aplicações possuem um método cuja execução é garantidamente a primeira a ocorrer. É geralmente dentro deste método que se realiza a criação dos singletons.
Vejamos um exemplo. Suponhamos que queremos testar a classe [ArticlesDaoPlainJdbc] anterior utilizando um teste JUnit. Uma classe de teste JUnit possui um método [setUp] que é executado antes de qualquer outro método. É aqui que iremos criar o singleton [ArticlesDaoPlainJdbc].
Se seguirmos a abordagem de passar informações de configuração através do construtor, teremos a seguinte classe de teste:
A classe de chamada [TestArticlesPlainJdbc] deve conhecer as quatro informações necessárias para inicializar o singleton [ArticlesDaoPlainJdbc] a ser construído.
Se seguirmos a abordagem de passar informações de configuração através de um ficheiro de configuração, poderíamos ter a seguinte classe de teste utilizando o ficheiro Spring descrito acima.
Aqui, a classe de chamada [TestSpringArticlesPlainJdbc] não precisa de saber as informações necessárias para inicializar o singleton a ser construído. Basta saber:
- [springArticlesPlainJdbc.xml]: o nome do ficheiro de configuração Spring descrito acima
- [articlesDao]: o nome do singleton a ser criado
Uma modificação no ficheiro de configuração, fora destas duas entidades, não tem impacto no código Java. Este método de configurar os objetos de uma aplicação é muito flexível. Para se configurar, a aplicação precisa de saber apenas duas coisas:
- o nome do ficheiro Spring que contém as definições dos singletons a criar
- os nomes desses singletons, que o código Java utiliza para obter uma referência aos objetos aos quais foram associados através do ficheiro de configuração
2.2. Injeção de Dependências e Inversão de Controlo
Vamos agora apresentar o conceito de Injeção de Dependências utilizado pelo Spring para configurar aplicações. O termo Inversão de Controlo (IoC) também é utilizado. Considere a construção do singleton [ArticlesManagerWithDataBase] na camada de negócios da nossa aplicação:
![]() |
Para aceder aos dados do SGBD, a camada de negócio deve utilizar os serviços de um objeto que implemente a interface [IArticlesDao], por exemplo, um objeto do tipo [ArticlesDaoPlainJdbc]. O código para a classe [ArticlesManagerWithDataBase] pode ser semelhante ao seguinte:
public class ArticlesManagerWithDataBase implements IArticlesManager {
// a data access instance
private IArticlesDao articlesDao;
....
public ArticlesManagerWithDataBase (String driverClassName, String url, String user, String pwd, ...) {
...
// creation of a data access service
articlesDao =(IArticlesDao)new ArticlesDaoPlainJdbc(driverClassName,url,user,pwd);
...
}
public ... doSomething(...){
...
}
}
A classe [ArticlesDaoPlainJdbc] deve implementar a interface [IArticlesDao] aqui:
Para criar o singleton [IArticlesDao] necessário para que a classe funcione, o seu construtor utiliza explicitamente o nome da classe que implementa a interface [IArticlesDao]:
Temos, portanto, uma dependência codificada no nome da classe no código. Se a classe que implementa a interface [IArticlesDao] fosse alterada, o código no construtor anterior teria de ser modificado. Temos as seguintes relações entre os objetos:
![]() |
A própria classe [ArticlesManagerWithDataBase] toma a iniciativa de criar o objeto [ArticlesDaoPlainJdbc] de que necessita. Voltando ao termo «inversão de controlo», podemos dizer que é ela que detém o «controlo» para criar o objeto de que necessita.
Se tivéssemos de escrever uma classe de teste JUnit para a classe [ArticlesManagerWithDataBase], poderia ficar mais ou menos assim:
A classe de teste cria uma instância da classe de negócio [ArticlesManagerWithDataBase], que, por sua vez, cria uma instância da classe de acesso a dados [ArticlesDaoPlainJdbc] no seu construtor.
A solução Spring elimina a necessidade de a classe de negócio [ArticlesManagerWithDataBase] conhecer o nome [ArticlesDaoPlainJdbc] da classe de acesso a dados de que necessita. Isto permite que a classe seja alterada sem modificar o código Java da classe de negócio. O Spring permite a criação simultânea de ambos os singletons: um para a camada de acesso a dados e outro para a camada de negócio. O ficheiro de configuração do Spring irá definir um novo bean:
A nova funcionalidade é o bean que define o singleton da classe de negócio a ser criada:
<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]
- Ao campo [articlesDao] do bean é atribuído um valor através da tag <property name="articlesDao">. Este é o campo definido na classe [ArticlesManagerWithDataBase]:
Para que o campo [articlesDao] seja inicializado pelo Spring e pela sua tag <property>, o campo deve seguir o padrão JavaBean e deve existir um método [setArticlesDao] para inicializar o campo [articlesDao]. Note que o nome do método deriva precisamente do nome do campo. Da mesma forma, existe frequentemente um método [get...] para recuperar o valor do campo. Aqui, trata-se do método [getArticlesDao]. Nesta nova versão, a classe [ArticlesManagerWithDataBase] já não possui um construtor. Já não necessita de um.
- O valor que o Spring atribuirá ao campo [articlesDao] é o do bean [articlesDao] definido no seu ficheiro 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 constrói o singleton [ArticlesManagerWithDataBase], também cria o singleton [ArticlesDaoPlainJdbc]:
- O Spring estabelecerá um gráfico de dependências dos beans e verificará que o bean [articlesManager] depende do bean [articlesDao]
- construirá o bean [articlesDao], ou seja, um objeto do tipo [ArticlesDaoPlainJdbc]
- depois, irá construir o bean [articlesManager] do tipo [ArticlesManagerWithDataBase]
Agora, imaginemos um teste JUnit para a classe [ArticlesManagerWithDataBase]. Pode ficar assim:
Vamos acompanhar o processo de criação dos dois singletons definidos no ficheiro Spring denominado [springArticlesManagerWithDataBase.xml].
- O método [setUp] acima solicita uma referência ao bean denominado [articlesManager]
- O Spring consulta o seu ficheiro de configuração e encontra o bean [articlesManager]. Se este já tiver sido criado, simplesmente devolve uma referência ao objeto (singleton); caso contrário, cria-o.
- O Spring deteta a dependência do bean [articlesManager] em relação ao bean [articlesDao]. Por isso, cria o singleton [articlesDao] do tipo [ArticlesDaoPlainJdbc] se este ainda não tiver sido criado (como singleton).
- Cria o singleton [articlesManager] do tipo [ArticlesManagerWithDataBase]
Este mecanismo pode ser representado graficamente da seguinte forma:
![]() |
Vamos relembrar a estrutura da classe [ArticlesManagerWithDataBase]:
Assim que o Spring terminar de construir os singletons, temos um objeto do tipo [ArticlesManagerWithDataBase] cujo campo [articlesDao] é inicializado sem que ele saiba como. Dizemos que injetamos uma dependência no objeto [ArticlesManagerWithDataBase]. Dizemos também que invertemos o controlo: já não é o objeto [ArticlesManagerWithDataBase] que toma a iniciativa de criar o objeto que implementa a interface [IArticlesDao] de que necessita; em vez disso, é a aplicação de nível superior (quando se inicializa) que se encarrega de criar todos os objetos de que necessita, gerindo as suas interdependências.
A principal vantagem de configurar o singleton [ArticlesManagerWithDataBase] através de um ficheiro Spring é que agora podemos alterar a classe de implementação correspondente ao campo [articlesDao] da classe [ArticlesManagerWithDataBase] sem modificar o seu código. Basta alterar o nome da classe na definição do bean [articlesDao] no ficheiro Spring:
passará a ser, por exemplo:
O bean [ArticlesManagerWithDataBase] funcionará com esta nova classe de acesso a dados sem sequer se aperceber.
2.3. Spring IoC na prática
2.3.1. Exemplo 1
Considere a seguinte classe:
A classe tem:
- dois campos privados, nome e idade
- métodos getter e setter para estes dois campos
- um método toString para recuperar o valor do objeto [Person] como uma string
- um método init que será chamado pelo Spring quando o objeto for criado, e um método close que será chamado quando o objeto for destruído
Para criar objetos do tipo [Person], utilizaremos o seguinte ficheiro Spring:
Este ficheiro será denominado config.xml.
- Ele define dois beans com as respetivas chaves "person1" e "person2" do tipo [Person]
- Inicializa os campos [name, age] para cada pessoa
- 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 os nossos testes, utilizaremos uma única classe de teste JUnit à qual iremos adicionar métodos sucessivamente. A primeira versão desta classe será a seguinte:
Comentários:
- Para recuperar os beans definidos no ficheiro [config.xml], utilizamos um objeto do tipo [ListableBeanFactory]. Existem outros tipos de objetos que permitem o acesso aos beans. O objeto [ListableBeanFactory] é obtido no método [setUp] da classe de teste e armazenado numa variável privada. Assim, estará disponível para todos os métodos de teste.
- O ficheiro [config.xml] será colocado no [ClassPath] da aplicação, ou seja, num dos diretórios pesquisados pela Máquina Virtual Java quando procura uma classe referenciada pela aplicação. O objeto [ClassPathResource] é utilizado para pesquisar um recurso no [ClassPath] de uma aplicação, neste caso o ficheiro [config.xml].
- O Spring pode utilizar ficheiros de configuração em vários formatos. O objeto [XmlBeanFactory] é utilizado para analisar um ficheiro de configuração no formato XML.
- O processamento de um ficheiro Spring devolve um objeto do tipo [ListableBeanFactory], neste caso o objeto bf. Com este objeto, obtém-se um bean identificado pela chave C através de bf.getBean(C).
- O método [test1] recupera e apresenta os valores dos beans com as chaves "person1" e "person2".
A estrutura do projeto Eclipse da nossa aplicação é a seguinte:

Comentários:
- A pasta [src] contém o código-fonte. O código compilado será colocado numa pasta [bin] que não é mostrada aqui.
- O ficheiro [config.xml] está localizado na raiz da pasta [src]. A compilação do projeto copia-o automaticamente para a pasta [bin], que faz parte do [ClassPath] da aplicação. É aqui que ele é procurado pelo objeto [ClassPathResource].
- A pasta [lib] contém três bibliotecas Java necessárias para a aplicação:
- 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] da aplicação
A execução do método [test1] do teste JUnit produz os seguintes resultados:
Comentários:
- O Spring regista vários eventos utilizando a biblioteca [commons-logging.jar]. Estes registos ajudam-nos a compreender melhor como o Spring funciona.
- O ficheiro [config.xml] foi carregado e, em seguida, processado
- A operação*
forçou a criação do bean [person1]. Podemos ver o registo do Spring relativo a isto. Como tínhamos escrito [init-method="init"] na definição do bean [person1], o método [init] do objeto [Person] criado foi executado. A mensagem correspondente é apresentada.
- A operação
exibiu o valor do objeto [Person] criado.
- O mesmo fenómeno ocorre com o bean-chave [person2].
- 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 [Person]. Se assim fosse, o método [init] teria sido exibido, o que não é o caso aqui. Este é o princípio do singleton. Por predefinição, o Spring cria apenas uma única instância dos beans no seu ficheiro de configuração. Trata-se de um serviço de referência a objetos. Se lhe for solicitada a referência a um objeto que ainda não tenha sido criado, ele cria-o e devolve uma referência. Se o objeto já tiver sido criado, o Spring devolve simplesmente uma referência ao mesmo.
- Note-se que não há qualquer vestígio do método [close] do objeto [Person], apesar de termos escrito [destroy-method=close] na definição do bean. É possível que este método só seja executado quando a memória ocupada pelo objeto for recuperada pelo coletor de lixo. Quando isso acontece, a aplicação já terminou e escrever no ecrã não tem qualquer efeito. A verificar.
Agora que abordámos os conceitos básicos de uma configuração Spring, poderemos avançar nas nossas explicações um pouco mais rapidamente.
2.3.2. Exemplo 2
Considere a seguinte nova classe [Car]:
A classe tem:
- três campos privados: type, make e owner. Estes campos podem ser inicializados e lidos utilizando os métodos públicos get e set. Também podem ser inicializados utilizando o construtor Car(String, String, Person). A classe possui ainda um construtor sem argumentos para cumprir a norma JavaBean.
- um método toString para recuperar o valor do objeto [Car] como uma string
- um método init que será chamado pelo Spring imediatamente após a criação do objeto, um método close que será chamado quando o objeto for destruído
Para criar objetos do tipo [Car], utilizaremos o seguinte ficheiro [config.xml] do Spring:
Este ficheiro adiciona um bean com a chave "car1" do tipo [Car] às definições anteriores. Para inicializar este bean, poderíamos ter escrito:
Em vez de escolher o método já apresentado, optámos aqui por utilizar o construtor Car(String, String, Person) da classe. Além disso, o bean [car1] define o método a ser chamado durante a construção inicial do objeto [init-method] e o método a ser chamado durante a destruição do objeto [destroy-method].
Para os nossos testes, utilizaremos a classe de teste JUnit já apresentada, adicionando-lhe o seguinte método [test2]:
O método [test2] recupera o bean [car1] e apresenta-o.
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 [car1]
- Linha 4: O Spring começa a criar o bean [car1] porque este bean ainda não foi criado (singleton)
- linha 6: como o bean [car1] faz referência ao bean [person2], este último é, por sua vez, construído
- Linha 7: o bean [person2] foi criado. O seu método [init] é então executado.
- Linha 9: O Spring indica que utilizará um construtor para criar o bean [car1]
- linha 10: o bean [car1] foi criado. O seu método [init] é então executado.
- linha 11: o método [test2] exibe o valor do bean [car1]
2.3.3. Exemplo 3
Apresentamos a seguinte nova classe [PersonGroup]:
Os seus dois membros privados são:
members: uma matriz de pessoas que são membros do grupo
workGroups: um dicionário que associa uma pessoa a um grupo de trabalho
Note-se aqui que a classe [PeopleGroup] não define um construtor sem argumentos para cumprir a norma JavaBean. Recorde-se que, na ausência de qualquer construtor, existe um construtor «padrão», que é o construtor sem argumentos que não faz nada.
O objetivo aqui é demonstrar como o Spring permite a inicialização de objetos complexos, tais como aqueles com campos de matriz ou dicionário. Adicionamos um novo bean ao ficheiro [config.xml] do Spring anterior:
- A tag <list> permite-lhe inicializar um campo do tipo array ou um que implemente a interface List com valores diferentes.
- A tag <map> permite fazer o mesmo com um campo que implemente a interface Map
Para os 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 apresenta-o.
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 [group1]
- linha 4: O Spring começa a criar este bean
- Como o bean [group1] faz referência aos beans [person1] e [person2], estes dois beans são criados (linhas 6 e 9) e os seus métodos init são executados (linhas 7 e 10)
- Linha 11: O bean [group1] foi criado. O 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
Queremos construir uma aplicação de três camadas com a seguinte estrutura:
![]() |
- As três camadas serão tornadas independentes através da utilização de interfaces Java
- A integração das três camadas será gerida pelo Spring
- Criaremos pacotes separados para cada uma das três camadas, aos quais daremos os nomes de Control, Domain e Dao. Um pacote adicional conterá as aplicações de teste.
A estrutura da aplicação no Eclipse poderá ser a seguinte:

2.4.2. A camada de acesso a dados DAO
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 irá devolver a+b, e o método Dao1Impl2.doSomethingInDaoLayer irá devolver a-b.
- Escreva uma classe de teste JUnit para testar as duas classes anteriores
2.4.3. A camada de negócios
A camada de negócios irá 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. Estas classes terão um construtor que recebe um parâmetro do tipo IDao1. O método Domain1Impl1.doSomethingInDomainLayer incrementará a e b em um, e depois passará estes dois parâmetros para o método doSomethingInDaoLayer do objeto IDao1 recebido. O método Domain1Impl2.doSomethingInDomainLayer, por outro lado, irá diminuir a e b em um antes de fazer o mesmo.
- Escreva uma classe de teste JUnit para testar as duas classes anteriores
2.4.4. A camada de interface do utilizador
A camada de interface do utilizador irá 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. Estas classes terão um construtor que recebe um parâmetro do tipo IDomain1. O método Control1Impl1.doSomethingInControlLayer incrementará a e b em um, e depois passará estes dois parâmetros para o método doSomethingInDomainLayer do objeto IDomain1 recebido. O método Control1Impl2.doSomethingInControlLayer, por outro lado, irá diminuir a e b em um antes de fazer o mesmo.
- Escreva uma classe de teste JUnit para testar as duas classes anteriores
2.4.5. Integração com o Spring
- Escreva um ficheiro de configuração Spring que determinará quais as classes que cada uma das três camadas anteriores deve utilizar
- Escreva uma classe de teste JUnit utilizando diferentes configurações do Spring para destacar a flexibilidade da aplicação
- Escreva uma aplicação autónoma (método main) que passe dois parâmetros para a interface IControl1 e exiba o resultado devolvido pela interface.
2.4.6. Uma solução
2.4.6.1. O projeto Eclipse

Os arquivos na 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. [Spring] Ficheiros de configuração
Um primeiro [springMainTest1.xml]:
Um segundo [springMainTest2.xml]:
2.4.6.6. O pacote de testes [istia.st.demo.tests]
Um teste [principal]:
Resultados apresentados na consola do Eclipse:
Outro teste utilizando o segundo ficheiro de configuração [Spring]:
Resultados apresentados na consola do Eclipse:
Por fim, um teste JUnit:
2.5. Conclusão
O framework Spring oferece verdadeira flexibilidade tanto na arquitetura da aplicação como na configuração. Utilizámos o conceito de IoC, um dos dois pilares do Spring. O outro pilar é o AOP (Programação Orientada a Aspetos), que não abordámos. Permite adicionar «comportamento» a um método de classe através da configuração, sem modificar o código do método. Em termos simples, o AOP permite filtrar chamadas a determinados métodos:
![]() |
- o filtro pode ser executado antes ou depois do método alvo M, ou ambos.
- O método M não tem conhecimento destes filtros. Estes são definidos no ficheiro de configuração do Spring.
- O código do método M não é modificado. Os filtros são classes Java que devem ser implementadas. O Spring fornece filtros predefinidos, particularmente para a gestão de transações DBMS.
- Os filtros são beans e, como tal, são definidos no ficheiro de configuração do Spring como beans.
Um filtro comum é o filtro de transação. Considere um método M na camada de negócios que realiza duas operações inseparáveis sobre os dados (uma unidade de trabalho). Ele chama dois métodos, M1 e M2, na camada DAO para realizar essas duas operações.
![]() |
Por residir na camada de negócios, o método M abstrai o armazenamento de dados subjacente. Por exemplo, não precisa de assumir que os dados estão armazenados num SGBD ou que deve incluir as chamadas aos métodos M1 e M2 dentro de uma transação do SGBD. Cabe à camada DAO tratar destes detalhes. Uma solução para o problema anterior é criar um método na camada DAO que, por sua vez, chame os métodos M1 e M2, envolvendo essas chamadas numa transação do SGBD.
![]() |
A solução de filtragem AOP é mais flexível. Permite-lhe definir um filtro que, antes de chamar M, iniciará uma transação e, após a chamada, executará um commit ou um rollback, conforme apropriado.
![]() |
Esta abordagem apresenta várias vantagens:
- uma vez definido o filtro, este pode ser aplicado a vários métodos, por exemplo, todos aqueles que requerem uma transação
- os métodos filtrados não precisam de ser reescritos
- uma vez que os filtros a utilizar são definidos através da configuração, podem ser alterados
Para além dos conceitos de IoC e AOP, o Spring fornece inúmeras classes de suporte para aplicações de três camadas:
- para JDBC, SQLMap (iBatis), Hibernate e JDO (Java Data Object) na camada DAO
- para o modelo MVC na camada de Interface do Utilizador
Para mais informações: http://www.springframework.org.









