Atenção: esse artigo tem um vídeo complementar. Clique e assista!

De que se trata o artigo:

Discutir o problema de acoplamento e testabilidade de código, introduzir o design pattern injeção de dependência como solução aos problemas apresentados, apresentar os frameworks de injeção de dependência Spring e Guice, e comparar as implementações de DI e AOP dos mesmos.


Para que serve:

Fornecer um meio para construção de objetos, reduzindo o acoplamento entre componentes, privilegiando a facilidade de manutenção e garantindo a testabilidade do código.


Em que situação o tema é útil:

Além de ser considerado uma boa prática de programação, o uso de injeção de dependências para reduzir o acoplamento aumenta a manutenibilidade do sistema e, consequentemente, a testabilidade do produto de software.

Google Guice: o novo Spring da Google?

Existem formas alternativas para criação de objetos sem utilizar diretamente o operador new. No artigo, a injeção de dependência é apresentada para a construção de código fracamente acoplado e testável. O framework Google Guice emprega a anotação @Inject para construir dependências definidas em um módulo de configuração. Através do projeto JavaConfig, o Spring Framework também permite a definição programática de módulos de configuração através da anotação @Bean. Entretanto, a implementação de injeção de dependência do Spring se revela menos invasiva ao código fonte. O mesmo pode ser dito sobre a implementação AOP do Spring em relação ao Guice.

O Spring Framework se consolidou no mercado como uma das principais soluções para projetos Java EE de baixo acoplamento. A principal premissa do Spring é delegar a criação de objetos de negócio ao container do framework. Sobre contextos definidos, a instanciação, configuração, destruição e mesmo a completa inferência de dependências (autowiring) destes beans é definida por meio de anotações (projeto JavaConfig) ou por um arquivo de configuração em formato XML. Notoriamente, a arquitetura do framework promove reusabilidade, facilita a construção de testes unitários (pela injeção de mocks) e surge como uma alternativa à complexidade existente no uso de EJBs. Esse framework open-source implementa ainda mecanismos de segurança, controle de transações e oferece diversos módulos especializados em desenvolvimento web, persistência, acesso remoto e programação orientada a aspectos (AOP).

Tendo em vista uma solução tão consolidada e conceituada como o Spring, seria algo surpreendente se uma empresa de referência no mercado de tecnologia propusesse um novo framework com funcionalidade semelhante.

Em março de 2007, o Google anunciou o Guice (pronuncia-se “juice”), definido pelo mesmo como “um framework leve para injeção de dependências”. Diferentemente do Spring, que possui um escopo abrangente sobre todas as camadas da aplicação, o Guice se concentra apenas na injeção de dependências, por meio de anotações, e AOP. No entanto, com o recente lançamento do Guice 2.0, o framework incorpora integração com Servlets, Struts 2, GWT (GIN) e GWT-RPC, OSGi e Google App Engine (middleware do ambiente distribuído Google), respondendo de forma mais ampla a questões intrínsecas de comunicação entre as camadas da aplicação. Parte do interesse no framework Guice provém de sua utilização em quase todos os projetos recentes do Google, tais como Google Waves, Adwords, GMail, Orkut, Google Docs, Youtube, etc.

Desta forma, a integração das ferramentas open source da empresa, ou a contribuição em suas comunidades de desenvolvedores, envolve o estudo do mesmo. Adicionalmente, a versão 2.0 é compatível com a plataforma Android (sem suporte a AOP).

Autowiring: O recurso de autowiring do framework Spring possibilita que as dependências dos beans sejam injetadas sem sua declaração explícita pelo desenvolvedor. Desta forma, as dependências são inferidas com base em seu tipo, nome, ou outro identificador.

GIN (google-gin ou GWT INjection): Componente open source que permite a utilização de injeção de dependências pelo framework Guice de forma integrada ao framework GWT, obtendo instâncias de beans em client side por meio de JavaScript.

Motivação: o que é Injeção de dependência?

Um dos aspectos importantes na arquitetura de uma solução é o desacoplamento do código. Um código desacoplado garante uma maior qualidade e facilita futuras mudanças. Nas palavras de Erich Gamma, coautor do JUnit, JDT e do famoso livro Padrões de Projeto: “programe para uma interface, não para uma implementação”. Assumindo as palavras de nosso estimado guru, nada mais adequado do que iniciar nosso estudo pela definição da interface de um serviço.

Seja o exemplo da Listagem 1: esta interface define um serviço de cobrança, que tem a responsabilidade de efetuar o pagamento de um pedido (ex.: uma lista de produtos num carrinho de compras) com um cartão (ex.: um cartão de crédito). O serviço deve se comunicar com a operadora do cartão (bandeira VISA, por exemplo), autorizar e faturar o pagamento e ainda retornar um recibo, a ser apresentado ao cliente.

Listagem 1. Interface do serviço de cobrança.


  package br.org.venturus.dependencyinjection.test;
   
  public interface CobrancaService { 
   
    Recibo efetuarPagamento(Pedido pedido, Cartao cartaoCredito);
   
  }

Note que toda a definição do serviço foi pensada pelas necessidades do negócio, e não por restrições de implementação ou mesmo do ambiente de desenvolvimento. Somente o ato de iniciar o desenvolvimento pela tradução do negócio no contrato das interfaces já é, em si, uma boa prática (embora fundamental para a componentização de sistemas em geral, esta prática é um dos fundamentos mais importantes no design de arquiteturas SOA).

A interface do serviço é fundamental na arquitetura, pois a mesma define as mensagens que poderão ser enviadas ao serviço. No entanto, a interface não implementa o serviço, ou seja, a interface não apresenta o código dos métodos que define e, por isso, não pode ser instanciada. É preciso uma classe concreta que implemente a interface do serviço, como o exemplo da Listagem 2.

Listagem 2. Classe concreta do serviço com criação de dependências através da chamada explícita do construtor.


  package br.org.venturus.dependencyinjection.test;
   
  public class CobrancaServiceImp implements CobrancaService {
    
    public Recibo efetuarPagamento(Pedido pedido, Cartao cartaoCredito) { 
     
      ProcessadorCartao processador = new ProcessadorCartaoVisa();
   
      try {
        Pagamento pagamento = processador.cobrar(cartaoCredito, pedido.getTotal());
        return pagamento.efetuado () ? 
          Recibo.forPagamentoEfetuado(pedido.getTotal()) :
          Recibo.forPagamentoNegado(pagamento.getMensagemPagamentoNegado());     
      } catch (UnreachableException e) {
        return Recibo.forErro(e.getMessage());    
      }  
   
    }
   
  }

No código da Listagem 2 ...

Quer ler esse conteúdo completo? Tenha acesso completo