Desenvolvimento - Java
Migrando Spring IOC com XML para IOC com anotação
Veja nesse artigo a migração de um sistema utilizando a inversão controle com Spring XML sendo migrada para a forma com anotações. O Spring permite duas formas de injeção de dependência, através de XML e anotação. Foi criado um sistema veicular para demonstrarmos isso.
por Diego Morais LeiteVeja nesse artigo a migração de um sistema utilizando a inversão controle com Spring XML sendo migrada para a forma com anotações. O Spring permite duas formas de injeção de dependência, através de XML e anotação. Foi criado um sistema veicular para demonstrarmos isso.
Ferramentas utilizadas:
- IDE Eclipse Kepler
- Java 6
- Spring Framework
- Apache Commons Logging
O download do framework pode ser feito no endereço: http://www.springsource.org/download/community
Para esse artigo foi utilizado a versão do Spring 3.2.3. Foi feito o download do arquivo spring-framework-3.2.3.RELEASE-dist.zip. Ao descompactar o arquivo, a pasta terá a seguinte estrutura:

Figura 1: Estrutura de pastas
Os jars do Spring estão localizados na pasta libs.
Veja que há vários jars nesta pasta. Nas versões recentes do Spring, o Spring Source separou as diversas comunidades que compõem o framework Spring, para que o desenvolvedor escolha somente o que lhe interessar, no nosso caso será apenas a injeção de dependência.
Observação: Nas versões anteriores do Spring, todos esses jars eram agrupados em apenas um jar.
Para o nosso projeto será necessário baixar o framework commons-logging da Apache. O Spring possui dependência desse framework. Este download pode ser feito no endereço: http://commons.apache.org/proper/commons-logging/download_logging.cgi
Os jars utilizados nesse artigo para o projeto Veicular, foram:

Figura 2: Jars da aplicação
Inversão de Controle com XML
Foi criado o projeto SpringProject no eclipse utilizando o Java 6. Primeiramente, o projeto utilizará a forma de XML para controle dos beans, ou seja, os beans serão declarados em arquivos de XML.
Assim o container do Spring registrará todos os beans e componentes descritos nesses arquivos.
Abaixo, a estrutura do projeto criado:

Figura 3: Estrutura do projeto com XML
Os jars utilizados, descritos acima, devem ser adicionados no Java Build Path do projeto. Qualque dúvida, acesse a url: http://www.wikihow.com/Add-JARs-to-Project-Build-Paths-in-Eclipse-%28Java%29
Os fontes do projeto estão disponíveis para download no final desse artigo. Mas segue abaixo, para simples conferência:
Listagem 1: Classe Main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package org.project.spring; import java.util.List; import org.project.spring.entity.Carro; import org.project.spring.factory.SingletonBeanFactory; import org.project.spring.service.VeiculoService; import org.springframework.beans.factory.BeanFactory; public class Main { public static void main(String args[]){ final BeanFactory beanFactory = SingletonBeanFactory.getBeanFactory(); final VeiculoService veiculoService = (VeiculoService)beanFactory.getBean( "veiculoService" ); final List<Carro> listaCarro = veiculoService.listarVeiculoPorMontadora( "Fiat" ); for (Carro carro : listaCarro){ System.out.println(carro.toString()); } } } |
Listagem 2: Classe VeiculoDAO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package org.project.spring.dao; import java.util.ArrayList; import java.util.List; import org.project.spring.entity.Carro; public class VeiculoDAO { private String qtdMaxima; public VeiculoDAO(String qtdMaxima){ this .qtdMaxima = qtdMaxima; } public List<Carro> findVeiculo(String montadora){ final List<Carro> listaCarro = new ArrayList<Carro>(); int maximo = Integer.parseInt( this .qtdMaxima); for ( int contador = 0 ; contador < maximo ; contador++ ){ listaCarro.add( new Carro(contador, "Punto" , montadora)); } return listaCarro; } } |
Listagem 3: Classe Carro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package org.project.spring.entity; public class Carro { private int id; private String nome; private String montadora; public Carro(int id, String nome, String montadora){ this .id = id; this .nome = nome; } public int getId() { return id; } public void setId(int id) { this .id = id; } public String getNome() { return nome; } public void setNome(String nome) { this .nome = nome; } public String getMontadora() { return montadora; } public void setMontadora(String montadora) { this .montadora = montadora; } @Override public String toString(){ return "Id: " + this .id+ " - Nome: " + this .nome; } } |
Listagem 5: Classe SingletonBeanFactory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package org.project.spring.factory; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SingletonBeanFactory { private static ApplicationContext applicationContext ; private SingletonBeanFactory() { /* Design pattern singleton */ } public static BeanFactory getBeanFactory() { if (applicationContext == null ) { applicationContext = new ClassPathXmlApplicationContext( new String[] { "org/project/spring/resource/spring/application-context.xml" }); } return applicationContext; } } |
Listagem 6: Classe VeiculoService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package org.project.spring.service; import java.util.List; import org.project.spring.dao.VeiculoDAO; import org.project.spring.entity.Carro; public class VeiculoService { private VeiculoDAO dao; public List<Carro> listarVeiculoPorMontadora(String montadora){ return dao.findVeiculo(montadora); } public VeiculoDAO getDao() { return dao; } public void setDao(VeiculoDAO dao) { this .dao = dao; } } |
Arquivo de Propriedade: veiculo.properties
1 | veiculo.quantidade.maxima=5 |
Listagem 7: Arquivo de configuração geral do Spring application-context.xml
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version= "1.0" encoding= "UTF-8" ?> <beans xmlns= "http://www.springframework.org/schema/beans" xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" > <context:property-placeholder location= "classpath:org/project/spring/resource/veiculo.properties" /> <import resource= "repository.xml" /> <import resource= "service.xml" /> </beans> |
Listagem 8: Arquivo de configuração de repositórios do Spring repository.xml
1 2 3 4 5 6 7 8 9 10 11 | <?xml version= "1.0" encoding= "UTF-8" ?> <beans xmlns= "http://www.springframework.org/schema/beans" <bean id= "veiculoDAO" class= "org.project.spring.dao.VeiculoDAO" > <constructor-arg index= "0" value= "${veiculo.quantidade.maxima}" /> </bean> </beans> |
Listagem 9: Arquivo de configuração de serviços do Spring service.xml
1 2 3 4 5 6 7 8 9 10 11 | <?xml version= "1.0" encoding= "UTF-8" ?> <beans xmlns= "http://www.springframework.org/schema/beans" <bean id= "veiculoService" class= "org.project.spring.service.VeiculoService" > <property name= "dao" ref= "veiculoDAO" /> </bean> </beans> |
Veja que a classe SingletonBeanFactory é um singleton responsável por obter referência ao container do Spring. Essa prática foi utilizada para que nessa aplicação, tenha apenas um container de beans.
Nesse singleton, foi utilizado a classe ClassPathXmlApplicationContext passando como parâmetro o caminho do arquivo XML geral. Essa classe do Spring é responsável por criar e gerenciar o container dos beans.
Outra característica desse aplicativo, foi a injeção de arquivo de propriedades(properties) em atributos de beans, como exemplo, a classe VeiculoDAO que teve o seu atributo qtdMaxima injetado com o valor da chave “veiculo.quantidade.maxima” do arquivo veiculo.properties.
Ao executar o arquivo Main.java, você obterá a seguinte saída:
1 2 3 4 5 | Id: 0 - Nome: Punto Id: 1 - Nome: Punto Id: 2 - Nome: Punto Id: 3 - Nome: Punto Id: 4 - Nome: Punto |
Inversão de Controle com Anotação
Trabalhando com o mesmo projeto SpringProject, foram feitas algumas alterações.
Abaixo, a nova estrutura do projeto:

Figura 4: Estrutura do projeto com anotação
O arquivo application-context.xml foi alterado e adicionado a tag componente-scan. Segue:
1 2 3 4 5 6 7 8 9 10 11 | <?xml version= "1.0" encoding= "UTF-8" ?> <beans xmlns= "http://www.springframework.org/schema/beans" xsi:schemaLocation= "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd" > <context:property-placeholder location= "classpath:org/project/spring/resource/veiculo.properties" /> <context:component-scan base-package= "org.project.spring.dao,org.project.spring.service,org.project.spring.resource" /> </beans> |
Veja que não é necessário mais importar os arquivos repository.xml e service.xml. O tag componente-scan faz com que o próprio framework detecte e instancie os beans, escaneando as classes dos packages definidos no atributo location. Dessa forma, não é mais necessário o desenvolvedor declarar manualmente os beans em arquivos XML.
O Spring escaneará e processará as anotações abaixo:
- @Component - Indica o component para beans em geral
- @Repository - Indica o DAO component para camada de persistência
- @Service - Indica o Service component para a camada de negócio.
- @Controller - Indica o Controller component para a camada de apresentação.
As principais camadas da aplicação possuem uma anotação, como a camada de serviço, persistência e apresentação. É uma boa prática a utilização dessas anotações para cada camada. Para as camadas em geral e outros beans, pode-se utilizar a anotação @Component.
No final, todas as anotações transformarão as classes anotadas em componentes do container Spring.
As classes VeiculoService e VeiculoDAO foram alteradas para receber a anotação.
Listagem 10: Classe VeiculoService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package org.project.spring.service; import java.util.List; import org.project.spring.dao.VeiculoDAO; import org.project.spring.entity.Carro; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class VeiculoService { @Autowired private VeiculoDAO dao; public List<Carro> listarVeiculoPorMontadora(String montadora){ return dao.findVeiculo(montadora); } public VeiculoDAO getDao() { return dao; } public void setDao(VeiculoDAO dao) { this .dao = dao; } } |
A anotação @Autowired atribuiu ao atributo dao da classe VeiculoService a referência do bean VeiculoDAO. Não foi necessário passar o nome do bean na anotação, pois ela própria pega o nome da classe para procurar no container.
Listagem 11: Classe VeiculoDAO
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | package org.project.spring.dao; import java.util.ArrayList; import java.util.List; import org.project.spring.entity.Carro; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Repository; @Repository public class VeiculoDAO { @Value( "${veiculo.quantidade.maxima}" ) private String qtdMaxima; public List<Carro> findVeiculo(String montadora){ final List<Carro> listaCarro = new ArrayList<Carro>(); int maximo = Integer.parseInt( this .qtdMaxima); for ( int contador = 0 ; contador < maximo ; contador++ ){ listaCarro.add( new Carro(contador, "Punto" , montadora)); } return listaCarro; } } |
Veja que para atribuir o valor de chaves de arquivos de propriedade ao atributo qtdMaximo, foi utilizado a anotação @Value passando como parâmetro "${veiculo.quantidade.maxima}", em que possui o nome da chave da propriedade.
Conclusão
Vimos como é simples a migração da Injeção de dependência da forma XML para a forma de anotação. O grande segredo é o tag component-scan.
Bom pessoal, até a próxima!