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
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
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
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
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
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
veiculo.quantidade.maxima=5
Listagem 7: Arquivo de configuração geral do Spring application-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <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
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <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:
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:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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
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
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!