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 Leite



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.

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:

Estrutura de pastas

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:

Jars da aplicação

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:

Estrutura do projeto com XML

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"?>
     
    <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"?>
  
    <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"?>
  
    <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:

Estrutura do projeto com anotação

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"?>
     
    <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!

Diego Morais Leite

Diego Morais Leite - Arquiteto de Sistemas Sênior. Formado em Processamento de Dados pela Faculdade de Tecnologia de Sorocaba. Engenheiro de Softwares pela Universidade Estadual de Campinas(UNICAMP). Desenvolve com a plataforma Java mais de 6 anos. Possui as certificações SCJP, SCWCD e SCBCD. Mestrando em Ciência da Computação pela UNICAMP. Ministra treinamentos para certificação Java e é Scrum Master de projetos ágeis. Trabalhou em projetos nas áreas de saúde, seguros, finanças e de controle de tráfego do espaço áereo brasileiro. Atualmente, presta serviços para financeiras.