Você está na página 1de 23

Guia itexto: Injeo de Dependncias com Spring Framework 3 pendncias http://devkico.itexto.com.

br

Injeo de Dependncias com Spring Framework 3


O objetivo deste guia expor o porqu, como usar e quais as melhores prticas relacionadas ao container de Injeo de Dependncias (Dependency Injection, ou DI do (Dependency DI) Spring Framework 3.0. O assunto pode interessar o leitor pelas seguintes razes: Trata-se do ncleo do Spring Framework: sendo assim conhecimento se obrigatrio para todos aqueles que desejem us-lo ou seus derivados. des Ainda mais importante: um padro de projeto que aumenta de forma significativa a qualidade dos sistemas nos quais aplicado. Mesmo que o leitor no se interesse pelo Spring Framework, poder us-lo em seus trabalhos adotand outros adotando containeres como Pico, miocc ou mesmo o seu prprio se for o caso.

Um projeto de software ruim costuma apresentar trs caractersticas rigidez, caractersticas: fragilidade e imobilidade. Frgil aquele sistema no qual ao se introduzir uma modificao nos deparamos com efeitos inesperados em outros de seus componentes. A rigidez conseqncia desta fragilidade: dada a dificuldade em se manter o sistema o fragilidade: desenvolvedor v suas opes de atuao limitadas (ou mesmo anuladas) J a mo anuladas). imobilidade diz respeito dificuldade em se extrair partes do sistema que possam ser reaproveitadas em outros projetos. Estes trs problemas possuem a mesma causa: o alto acoplamento. Um sistema considerado de alto acoplamento quando seus componentes internos so fortemente quando dependentes. Por componentes devem ser entendidas classes, fontes de dados, sistemas externos ou internos. Para melhor entender o problema vamos usar um exemplo bastante trivial que ser um software que busque ttulos de livros escritos por determinado autor. Na imagem 1 usque podemos ver sua estrutura inicial. inicial

Caminhando para a Injeo de Dependncias

Imagem 1 - Nosso modelo inicial

Na classe cliente temos um nico mtodo chamado buscar(), que faz uma chamada , funo buscaPorAutor da classe DAOLivro que encontra ttulos de livros escritos p pelo nome do autor passado como parmetro. Imaginemos por um momento que DAOLivro parmetro usa como fonte de dados um arquivo texto. Por anos este sistema poder funcionar sem problemas. Mas e se no futuro fosse problemas necessrio usar alguma outra fonte de dados, digamos, um banco de dados relacional? dados, Podemos imaginar duas solues que no usem orientao a objetos para resolver o problema: Na classe DAOLivro poderamos criar um novo mtodo chamado buscaPorAutorNoSGBD, que faria a consulta usando um banco de dados relacional. No , uma soluo interessante, pois estaramos aumentando a complexidade da classe incluindo uma nova funo que do ponto de vista das classes cliente, exerceria a mesma que, funo de buscaPorAutor. Tambm podemos alterar a funo buscaPorAutor incluindo um novo parmetro no qual pudssemos definir qual a fonte de dados a ser usada. De novo cairamos no mesmo problema da soluo anterior.

Guia itexto: Injeo de Dependncias com Spring Framework 3 pendncias http://devkico.itexto.com.br

Dado que estamos lidando com a plataforma Java e esta em sua essncia orientada a objetos, uma soluo mais interessante adotar o padro factory. A imagem 2 solu expe um segundo modelo proposto para nosso sistema.

Imagem 2 - Aplicando o padro Factory

O que : Padres de Projeto :


O conceito de padres de projeto foi cunhado por Cristopher Alexander no contexto da arquitetura civil e posteriormente adaptado para o desenvolvimento de software orientado a objeto1. Trata-se de solues para rmente problemas recorrentes na criao de software que possuem solues padronizadas e fornecem um vocabulrio em comum para todos aqueles que os aplicam. Um exemplo de padro de projeto o Factory, descrito neste artigo. exemp ,

O que : Padro de Projeto Factory :


O padro factory fornece uma interface para criao de famlias de objetos correlatos ou dependentes. Uma possvel implementao do padro a que apresentamos neste artigo: cria-se uma classe cujo nico objetivo se criar novas instncias de objetos que implementem determinada interface, fazendo com que apenas uma nica classe do sistema venha a ter dependncias diretas com todas as implementaes presentes de determinada classe determinada ou interface.

Nesta nova arquitetura a classe Cliente depende agora da interface IDAOLivro e da classe FactoryDAOLivro, a segunda responsvel por instanciar a implementao correta de IDAOLivro a partir do nome da fonte de dados fornecida pela classe Cliente ao chamar a funo criarIDAOLivro A soluo adotada apresenta vantagens bastante criarIDAOLivro. interessantes: A classe Cliente dependente apenas da interface IDAOLivro, e no de uma implementao especfica. Sendo assim agora possvel trabalhar com qualquer fonte de . dados imaginvel, desde que implemente a interface IDAOLivro. A responsabilidade pela instanciao de objetos que implementem a interface IDAOLivro fica centralizada em uma nica classe, reduzindo significativamente a complexidade do sistema.

O termo se consagrou na disciplina de engenharia de software com o livro Padres de Projeto de Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides (os quatro autores tambm so conhecidos como a d Gangue dos Quatro (Gang of Four ou GoF em ingls)

Guia itexto: Injeo de Dependncias com Spring Framework 3 pendncias http://devkico.itexto.com.br

O que vimos no segundo modelo na realidade a aplicao do princpio de inverso de dependncias cunhado por Robert C. Martin em 1996 no seu artigo The Dependency Invertion Principle2. Este princpio nos diz duas coisas: Um mdulo de nvel mais alto jamais deve depender diretamente de outro pertencente a um nvel inferior, mas sim de uma abstrao. m Abstraes no devem depender de detalhes de implementao, mas sim o contrrio Em nosso exemplo a classe Cliente um mdulo de nvel superior: no lhe interessa como os ttulos dos livros so obtidos, mas sim que os mesmos sejam retornados de alguma forma para que possa concluir o seu trabalho. No primeiro modelo, esta dependia diretamente de uma implementao especfica (o arquivo no formato textual J textual). na segunda, passa a depender apenas de uma abstrao que, no caso, a nossa interface IDAOLivro. O segundo postulado tambm foi respeitado no segundo modelo. Observe que as distintas implementaes de IDAOLivro no influenciam de forma alguma esta i interface, mas sim o contrrio. No caso, todas as implementaes especficas de IDAOLivro seguem rigidamente as regras definidas pela interface que, no caso, trata trata-se da obrigatoriedade de se implementar a funo buscaPorAutor. Observe que as trs caractersticas presentes em um design ruim no se aplicam no caractersticas segundo modelo. Nosso software no mais frgil, pois caso seja feita qualquer alterao em uma implementao especfica da interface IDAOLivro no afetar diretamente a classe Cliente. Como conseqncia, o sistema agora mais fcil de ser mantido (no h conseqncia, rigidez) e, ainda mais interessante: obtivemos mobilidade, pois podemos agora transportar com maior facilidade elementos do nosso sistema para outros projetos. Mas este modelo ainda est longe do ideal, porque aumentamos o grau de acoplamento da classe Cliente. Enquanto na primeira verso sua nica dependncia era a Cliente. classe DAOLivro, no segundo inclumos outra que a classe FactoryIDAOLivro hora , FactoryIDAOLivro. de apresentar uma terceira verso do sistema, cuja arquitetura exposta na imagem 3 ar 3.

Imagem 3 - Terceira verso do nosso modelo

A mudana foi sutil: apenas explicitamos a presena de um atributo daoLivro na classe Cliente do tipo IDAOLivro, cuja instncia definida pelo construtor da classe IDAOLivro, Cliente3. Agora podemos dizer que atingimos o menor grau de acoplamento possvel para esta classe. Porm, por mais que nos esforcemos, se continuarmos seguindo esta linha de raciocnio sempre nos depararemos com problemas de acoplamento. Basta observar a classe FactoryDAOLivro, que possui como dependncia todas as implementaes , todas presentes no sistema da interface IDAOLivro. quase certo que conforme este sistema . evolua chegaremos a um momento no qual a classe FactoryDAOLivro se tornar um
Este belssimo artigo encontra-se encontra se acessvel gratuitamente no http://www.objectmentor.com/publications/dip.pdf http://www.objectmentor.com/publications/dip.pd 3 Poderamos tambm ter criado um setter para este atributo, porm o efeito seria o mesmo.
2

endereo

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

monstro de difcil manuteno. A cada nova implementao de IDAOLivro precisaremos alter-la e compil-la novamente.

Alm deste problema, temos outro: necessria uma classe que crie uma instncia de Cliente. Esta, por sua vez, possui o mesmo problema apresentado no modelo 2: duas dependncias. Resumindo: chegamos ao limite do que podemos fazer usando apenas o padro Factory.

Entra a Injeo de Dependncias


A injeo de dependncias (Dependency Injection ou DI em ingls) uma forma de inverso de controle na qual o aspecto a ser invertido , como o prprio nome j diz, a resoluo de dependncias. Ao invs do desenvolvedor definir manualmente quais as instncias a serem criadas e injetadas, como fizemos nos trs modelos anteriormente descritos, delega-se esta tarefa a um container de inverso de controle (IoC) veja o quadro Injeo de Dependncias ou Inverso de Controle? -, evitando assim a necessidade de se implementar o padro factory. Grosso modo, podemos pensar no container de IoC como um factory ideal, capaz de instanciar qualquer tipo de classe sem que fiquemos presos a uma famlia especfica de objetos. Porm, como veremos, no caso do Spring este factory vai alm medida que tambm controla o ciclo de vida dos objetos por ele gerenciados. Para introduzirmos o conceito, imagine que este container uma classe mgica que sempre nos retorna um objeto cujo tipo exatamente aquele que estamos precisando. O truque por trs desta mgica ser exposto no decorrer deste artigo.

O que uma dependncia?


muito raro encontrarmos um software real e til composto por uma nica classe. Na esmagadora maioria das vezes topamos com classes que possuem atributos cujo tipo so outras classes. Estes atributos que referenciam outros tipos de classe so o que costumamos chamar de dependncia.

Injeo de Dependncias ou Inverso de Controle?


Se o ncleo do Spring chamado de Container de Inverso de Controle (IoC de Inversion of Control em ingls), porque estamos usando o termo injeo de dependncias? Porque como bem observou Martin Fowler em seu artigo Inversion of Control Containers and the Dependency Injection Pattern 4, os containeres de inverso de controle como Spring, Pico e outros aplicam um tipo muito especfico de inverso de controle.

E neste momento uma segunda pergunta surge: o que inverso de controle? Chama-se de inverso de controle a tcnica de desenvolvimento na qual um aspecto comportamental do sistema delegado a uma entidade externa. Um exemplo de inverso de controle o EJB. O desenvolvedor implementa o seu EJB e em seguida faz o deploy no servidor de aplicaes sem precisar se preocupar com o modo como seu componente ser iniciado, finalizado e gerenciado, porque neste caso tudo feito pelo servidor. Ao invs de nos preocuparmos com estas tarefas as delegamos a uma entidade externa, que normalmente recebe o nome de container. A inverso de controle esta no ncleo do conceito de framework. Ao adotarmos um framework, estamos reutilizando a estrutura de uma aplicao semi-pronta que finalizamos ao inserir nossos prprios componentes
4

O artigo pode ser online neste endereo: http://www.martinfowler.com/articles/injection.html

Guia itexto: Injeo de Dependncias com Spring Framework 3 pendncias http://devkico.itexto.com.br

customizados. No caso de aplicaes web este comportamento fica ntido quando ados. nos lembramos do processo de preenchimento de formulrios, que delegado ao framework ao invs de ser implementado manualmente pelo desenvolvedor. Aps estes exemplos fica ntido portanto que o termo Inverso de Controle ntido, genrico demais para ser adotado no caso do Spring, aonde o foco a resoluo das dependncias das classes de nosso projeto. Voltando ao nosso exemplo inicial, ao aplicarmos o padro de injeo de dependncias acabaramos com uma arquitetura similar exposta na imagem 4 Observe 4. que o Container no possui nenhuma dependncia direta com nenhuma das c classes do nosso sistema. Outro fator interessante a ser observado a ausncia da classe FactoryDAOLivro.

Imagem 4 - Nosso modelo aps aplicar Injeo de Dependncias

No novo modelo todo o processo de instanciao e preenchimento de dependncias odelo feito pelo container, que instrudo a faz-lo a partir de configuraes que podem estar faz nos mais variados formatos, desde arquivos no formato XML at anotaes em cdigo fonte. A partir destes dados e usando o mecanismo de reflexo provido pelo ambiente o computacional o container capaz de instanciar e injetar todas as dependncias que ns o instruamos a faz-lo. Uma das grandes vantagens deste modelo que neste estgio o desenvolved se desenvolvedor encontra prximo do desacoplamento quase total entre seus componentes. Como conseqncia, temos sistemas com qualidade muito superior, mais fceis de manter e , distribuir nas mais variadas situaes. Caso surja a necessidade de uma nova implementao de alguma das abstraes ja presentes no sistema, tudo o que o desenvolvedor precisa fazer implement-la, distribuimplement la, la como um arquivo. jar (ou .class mesmo), incluir a implementao no classpath do sistema e em seguida alterar o(s) arquivo(s) de configurao do container sem a o necessidade de recompilar o sistema para se adequar a esta nova situao. Obtm desta Obtm-se maneira mobilidade total do sistema, visto que com o ncleo pronto e estabilizado o processo de recompilao se torna uma tarefa muito mais rara de ser executada.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Spring Framework entra em cena

O objetivo do Spring Framework simplificar o desenvolvimento de aplicaes

Imagem 5 Componentes do Spring Framework. Nosso foco no Core Container

corporativas. Na imagem 5 podemos ver todos os mdulos que compem o framework, que uma alternativa vivel plataforma Java Enterprise Edition. Este incrvel framework possibilitou usando apenas POJOs obter os mesmos resultados que at ento s eram possveis com EJB. E tudo isto graas aplicao do conceito de injeo de dependncias! Spring pode fazer inmeras coisas, mas quando nos focamos apenas no seu ncleo, percebemos que estamos lidando na realidade com um container de injeo de dependncias e programao orientada a aspectos leve. Para melhor entender a sua definio, convm estudar suas partes. Por que leve? Spring no intrusivo. Se sua aplicao baseada no Spring, possvel que suas classes no venham a ter qualquer dependncia direta com o framework. Nada mais natural, visto que o problema do alto acoplamento justamente o que o conceito de injeo de dependncias visa resolver. Programao orientada a aspectos? O Spring oferece desde sua primeira verso suporte a programao orientada a aspectos. Esta uma tcnica poderosa que permite ao desenvolvedor separar a lgica de negcios de servios de infra-estrutura presente em nossa aplicao. importante mencionar esta caracterstica, visto que se trata do outro pilar do framework alm do container de injeo de dependncias. Porm nosso foco o container de injeo de dependncias. Sendo assim, iremos tratar aqui apenas do mdulo Core Container do Spring. Como ser visto, uma ferramenta que consegue ser ao mesmo tempo extremamente poderosa e simples de se usar. E esta a beleza deste container.

Guia itexto: Injeo de Dependncias com Spring Framework 3 pendncias http://devkico.itexto.com.br

Chegou o momento de colocar toda esta teoria em prtica. Para usar o container de colocar injeo do Spring necessrio baixar a ltima verso do framework em seu site oficial5. Para este artigo ser usada a verso 3.0.2. O Spring um framework extremamente modular. Isto quer dizer que no precisamos usar todos os arquivos JAR que que acompanham a distribuio.

O container de injeo de dependncias

As dependncias do Container Iremos usar apenas os arquivos que compem o Core Container do Spring. Na distribuio oficial estes so nomeados seguindo o seguinte padro: org.springframework. org.springframework. [nome do mdulo].[nmero da verso].RELEASE.jar. Sendo assim, o arquivo org.springframework. beans.3.0.2.RELEASE.jar por exemplo na realidade o mdulo beans. Precisaremos, portanto dos mdulos beans, context, context.support, core e expression. A nica dependncia externa do container a biblioteca Commons Logging, . que pode ser obtida em seu site oficial6. Dever ser adicionado o arquivo commons commonslogging-[nmero da verso].jar em seu classpath. [nmero Como o container funciona

Imagem 6 Funcionamento de um container

Para que o container seja til, primeiro precisamos configur-lo. No caso do Spring, er . suas configuraes podem vir de basicamente trs fontes: arquivos no formato XML (que a opo mais comum), anotaes em cdigo fonte ou programaticamente7. Uma vez alimentado com estas configuraes, o container ir armazenar co , internamente representaes dos objetos a serem gerenciados. Estas representaes definem quais classes devem ser instanciadas, suas interdependncias. Pense nas configuraes como uma receita a ser seguida pelo Spring quando for necessrio g instanciar um bean. Estas receitas de beans no entanto dizem mais do que apenas quais classes instanciar e suas interdependncias: definem tambm o escopo de cada bean. Escopos especificam qual deve ser o tempo de vida, ou seja, quando um bean j instanciado dever vida uando ser removido do container. De imediato o Spring nos fornece 5 tipos de escopo: singleton, . prototype, request, session e global session. Destes, apenas trataremos dos dois primeiros, session visto que os demais so usados no desenvolvimento de aplicaes web, o que foge do desenvolvimento foco do nosso artigo. Na tabela 1 possvel conhecer a descrio destes 5 escopos.

http://www.springframework.org http://commons.apache.org/logging/ - Na escrita deste artigo a ltima verso disponvel a 1.1. 7 O ncleo do Spring totalmente desacoplado de uma fonte especfica de configuraes. Sendo assim o desenvolvedor pode criar os seus prprios parsers de configurao caso seja de seu interesse. prprio
6

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Tabela 1 Escopos do Spring

Escopo singleton

Descrio Trata-se do escopo default do Spring. O container mantm uma nica instncia do bean definido. prototype O Spring sempre retorna uma nova instncia do bean caso o mesmo seja requerido. request Usado em aplicaes web, define que a instncia do bean possuir o mesmo tempo de vida que uma requisio HTTP session Adotado em aplicaes web, define que a instncia do bean se encontrar armazenada na sesso do usurio, sendo imediatamente destrudo junto com esta. global session Tambm usado em aplicaes web, armazena a instncia do bean em uma sesso global. Configurado e pronto para o uso, entra a classe cliente, que simplesmente far requisies ao container do Spring por um bean especfico.

Instanciando o Container
O Spring oferece dois tipos de container: BeanFactory e ApplicationContext. Nossa primeira boa prtica portanto diz respeito a qual tipo dever ser selecionado. BeanFactory na realidade uma interface, presente no pacote org.springframework.beans.factory que representa o container mais simples fornecido pelo framework, oferecendo apenas suporte a injeo de dependncias e gerenciamento de ciclo de vida dos beans. O framework j vem com algumas implementaes desta interface, sendo a mais usada org.springframework.beans.factory.xml.XmlBeanFactory, que l as configuraes do container a partir de um documento XML. Normalmente opta-se por usar o BeanFactory quando o ambiente computacional oferece restries mais incisivas como por exemplo um Applet. J ApplicationContext, que tambm uma interface presente no pacote org.springframework.context uma extenso de BeanFactory e oferece todos os servios deste e mais alguns como internacionalizao, extensibilidade e gerenciamento de eventos. As implementaes mais usadas desta interface so ClassPathXmlApplicationContext e FileSystemXmlApplicationContext. Ambas consomem suas configuraes a partir de documentos no formato XML e encontram-se no pacote org.springframework.context.support. A diferena entre uma e outra apenas aonde os documentos XML se encontram. Enquanto a primeira o busca no classpath da aplicao a outra o encontra no sistema de arquivos no qual a aplicao executada. Na esmagadora maioria das vezes voc acabar usando ApplicationContext, a no ser que possua excelentes razes para no faz-lo. Sendo assim, no transcorrer deste artigo usaremos apenas ApplicationContext. H uma diferena de comportamento entre BeanFactory e ApplicationContext. No caso do ApplicationContext todos os beans com escopo singleton so automaticamente carregados por default, ao contrrio de BeanFactory, em que beans pertencentes a este escopo s so inicializados na primeira vez em que so requeridos. Esta uma das razes pelas quais se costuma usar BeanFactory.

Uma das principais vantagens do Spring ser leve, sendo assim devemos proteger esta caracterstica ao mximo possvel. De preferncia, apenas uma classe dever

Oculte seu Container

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

referenciar o container do Spring, ocultando-o do restante do sistema. Na listagem 1 podemos ver como obter este resultado. uma classe muito simples mas que nos diz muita coisa.
Listagem 1: Ocultando o Container de Injeo de Dependncias
public class Container { private ApplicationContext contextoSpring; private ApplicationContext getContextoSpring() { if (contextoSpring == null) { contextoSpring = new ClassPathXmlApplicationContext("di/spring.xml"); } return contextoSpring; } public Object getBean(String nome) { ApplicationContext contexto = getContextoSpring(); if (contexto != null) { try { return contexto.getBean(nome); } catch (NoSuchBeanDefinitionException ex) { return null; } } return null; } public static synchronized Container getInstancia() {return _instancia;} private static Container _instancia = new Container(); private Container() {} }

O processo de instanciao do container caro do ponto de vista computacional. Sendo assim, interessante mantermos uma nica instncia de nosso ApplicationContext, o que conseguimos a partir da implementao do padro singleton na classe Container. Assim garantimos que uma nica instncia do container ser usada durante todo o processo de execuo do nosso sistema.

O que : Padro de Projeto Singleton


O padro de projeto Singleton tem como objetivo garantir que uma nica instncia de uma classe seja criada, alm de tambm fornecer um nico ponto de acesso a mesma. Seu uso um tanto quanto controverso, sendo normalmente usado apenas em situaes como a exposta na listagem 1 deste artigo.

Na listagem 1 tambm vemos basicamente tudo o que voc precisa saber a respeito de como obter um bean gerenciado pelo container. Basta executar a funo getBean, que recebe como parmetro o nome do bean presente no container. Seu valor de retorno do tipo Object. Se no container no houver um bean com este nome, ser disparada uma exceo do tipo org.springframework.beans.factory.NoSuchBeanDefinitionException, razo pela qual lidamos com esta exceo dentro da funo getBean. Observe que a classe Container possui apenas um nico mtodo pblico, no caso, getBean. Isto nos ajuda a garantir que nenhuma outra classe do projeto venha a ter uma dependncia direta com o Spring, garantindo assim a leveza do framework.

Alimentando o Container com XML


Para que o container possa nos retornar um bean, antes ele precisa saber o que e como instanciar. E neste momento que a configurao entra em cena. Tal como dito anteriormente, h basicamente trs maneiras de se configurar o Spring: atravs de documentos no formato XML, usando anotaes ou programaticamente.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Cada uma destas abordagens apresenta suas vantagens e desvantagens, que veremos no transcorrer deste artigo, porm dada sua natureza, interessante comear pela configurao via XML, pois esta expe todos os recursos do Spring que sero expostos no restante deste artigo. Na listagem 2 podemos ver como nossa aplicao inicial pode ser configurada usando este formato.
Listagem 2: Configurao do Spring de nossa aplicao Inicial
<?xml version="1.0" encoding="ISO-8859-1"?> <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.0.xsd"> <bean id="cliente" class="di.Cliente"> <property name="daoLivro" ref="daoLivro"/> </bean> <bean id="daoLivro" class="di.DAOLivroTexto" scope="prototype"> <property name="arquivo" value="/livros.txt"/> </bean> </beans>

O elemento raiz do documento beans. Cada bean gerenciado pelo container definido pela tag bean. Na listagem 2 podemos ver nossa aplicao configurada para trabalhar com um uma implementao de IDAOLivro que usa como fonte de dados um arquivo textual. O atributo bean possui apenas um atributo obrigatrio, que o class, que especifica qual classe dever ser instanciada. O atributo id usado para nomear os beans gerenciados pelo container. Sendo assim, na listagem 2 definimos dois beans: cliente e daoLivro. No bean cliente podemos ver a aplicao da injeo de dependncias. No interior da tag bean que o representa, h a tag property. Esta tag possui o atributo obrigatrio name, que identifica qual o nome da propriedade que dever ser atribuda pelo container. Spring utiliza o padro JavaBeans. Sendo assim a classe Cliente dever possuir um setter para a propriedade daoLivro, o que de fato possui, tal como pode ser conferido na listagem 3. Na tag property observa-se um outro atributo: ref. O valor deste atributo o nome do bean que dever ser injetado que, no caso, o bean daoLivro. interessante observar que a tag property tambm usada para definir o valor de propriedades do tipo string ou primitivas de um bean. Observe que na listagem 2 definimos a propriedade arquivo do bean daoLivro com o valor /livros.txt usando o atributo value. Caso o atributo seja do tipo numrico o Spring se encarregar de fazer a converso necessria para o usurio.
Listagem 3 A classe Cliente
public class Cliente {

private IDAOLivro daoLivro; public IDAOLivro getDaoLivro() { return this.daoLivro; } public void setDaoLivro(IDAOLivro dao) { this.daoLivro = dao; } public void buscar(String valor) { List<String> titulos = getDaoLivro().getLivrosAutor(valor); for (String titulo : titulos) { System.out.println(titulo); } } public Cliente() {} public Cliente(IDAOLivro dao) { setDaoLivro(dao);

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

} }

Os tipos de injeo de dependncia No Spring a injeo de dependncias pode ser feita de duas formas: por setter ou construtor. Acima acabamos de ver a injeo por setter. Este tipo de injeo executado em duas etapas. Na primeira o construtor default da classe definida par ao bean executado, gerando uma nova instncia para, em seguida, serem executados os setters definidos pelas tags property presentes no interior da tag bean. Sendo assim, quando for adotar a injeo de dependncias por setter, obrigatria a presena do construtor default. J a injeo de dependncias por construtor feita definindo-se qual construtor dever ser executado ao criarmos uma nova instncia do bean. A listagem 4 expe como o mesmo efeito que obtivemos usando a injeo por setter pode ser obtido ao adotarmos a injeo por construtor.
Listagem 4 Injeo de dependncias por construtor
<!Definindo o construtor por tipo <bean id="clientePorTipo" class="di.Cliente"> <constructor-arg type="di.IDAOLivro" ref="daoLivro"/> </bean> <!Definindo pela ordem do atributo do construtor <bean id=clientePorOrdem class=di.Cliente> <constructor-arg index=0 ref=daoLivro/> </bean>

Para fazer a injeo por construtor usamos a tag constructor-arg. H duas opes para se definir quais os valores de cada atributo do construtor. A mais recomendada por tipo. Neste caso constructor-arg dever receber um atributo chamado type (tal como na listagem 4) que identifique qual o tipo do argumento. O segundo atributo poder ser tanto ref, caso estejamos referenciando outro bean quanto value se estivermos nos referindo a um atributo primitivo ou string. A segunda opo definir os valores dos atributos do construtor a partir de sua ordem. Na listagem 4 podemos ver como isto feito no bean clientePorOrdem . No caso, ao invs de usarmos o atributo type, usamos index, que define qual atributo a partir da sua ordem (sempre iniciando a partir do zero). Esta opo til para se evitar ambigidade na escolha do construtor caso haja mais de um parmetro pertencente a um mesmo tipo. Injeo por setter ou construtor? Como regra geral, opta-se pela injeo por construtores para as dependncias obrigatrias e injeo por setter para as dependncias opcionais. Os puristas preferem a injeo por construtores porque assim temos a garantia de que ao obtermos um bean, estamos lidando com uma instncia completa, com todas as dependncias obrigatrias preenchidas. No entanto, a equipe de desenvolvimento do Spring incentiva a injeo por setter, pois assim evita-se a criao de construtores com vrios atributos, alguns dos quais definindo inclusive dependncias opcionais. uma maneira de influenciar os desenvolvedores a evitarem a escrita destes construtores que acabam dificultando a manuteno. Outra vantagem da injeo por setter que ela nos permite reconfigurar a instncia aps obtida, visto que tudo o que o desenvolvedor precisa fazer passar uma nova dependncia ao setter em questo. Se a pergunta vou precisar alterar alguma dependncia de minha instncia aps obtida? for positiva, a injeo por setter dever ser adotada.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Dando nome aos beans No precisamos nomear um bean. Caso no o faamos, o prprio Spring ir criar um nome interno para o bean mapeado e, caso este bean sem nome seja o nico de seu tipo, isto , o nico bean pertencente a determinada classe, podemos inclusive obt-lo usando o mtodo sobrescrito getBean(Class classe) do ApplicationContext. Mas esta obviamente no a melhor alternativa. Afinal de contas, nosso sistema pode crescer, e outros beans pertencentes mesma classe podem acabar no nosso arquivo de configurao. E neste caso, ao tentar obter um bean pela sua classe ao invs de pelo seu nome, obteramos uma exceo do tipo org.springframework.beans.factory.NoSuchBeanDefinitionException nos informando que h mais de um bean mapeado para aquele tipo especfico. Sendo assim fundamental saber como dar nome aos nossos beans. A classe bean possui dois atributos para que possamos executar esta tarefa. O primeiro deles j vimos nas listagens 2 e 4. Trata-se do atributo id. Usamos este atributo quando queremos definir um nome nico para nossos beans. Ao definirmos este atributo para o bean, garantimos que em nosso container s poder existir um bean como aquele nome. uma boa prtica us-lo por outra razo: alguns parseadores de XML oferecem otimizaes para este atributo, o que pode nos proporcionar ganhos em performance e validao destes documentos, visto que o atributo id o mesmo definido na especificao do formato XML pelo W3C. Nossa outra opo o atributo name, que nos permite dar um ou mais nomes para um bean. tambm usado quando necessrio nomear um bean usando caracteres especiais, o que no permitido na especificao XML. No caso de um bean possuir mais de um nome, estes podem ser separados por espao, ponto e vrgula (;) ou vrgulas (,). Na listagem 5 podemos ver alguns exemplos.
Listagem 5 Um bean com mais de um nome
<bean name=cliente;exemplo class=di.Cliente></bean> <bean name=cliente exemplo class=di.Cliente></bean> <bean name=cliente,exemplo class=di.Cliente></bean>

comum oferecer mais de um nome a um determinado bean em projetos maiores, nos quais possam ocorrer situaes nas quais times diferentes trabalhem em subsistemas distintos a serem integrados. Porm, na esmagadora maioria das vezes o ideal que cada bean possua um nico nome a fim de se evitar excessos de nomenclatura que acabem por gerar confuses dentro da equipe. uma boa prtica adotar padres de nomenclatura aos beans. Um padro bastante adotado o de se aplicar prefixos aos nomes dos beans que exponham sua finalidade, como por exemplo o prefixo dao a todos os beans que implementem o padro de projeto DAO.

Modularizando a configurao Uma das principais crticas configurao no formato XML a extenso que estes documentos possam vir a tomar. Realmente, um tanto trabalhoso dar manuteno em arquivos gigantescos, porm possvel sanar este problema dividindo a configurao em arquivos distintos. Nestes casos cada arquivo de configurao pode representar uma camada lgica do sistema ou um mdulo de sua arquitetura. H duas maneiras de se modularizar a configurao. A primeira delas atravs da tag <import>, que pode ser inserida em seus documentos XML tal como exemplificado na listagem 6.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Listagem 6 Usando a tag <import>


<beans> <import resource=servicos.xml/> <import resource=dao/daos.xml/> <bean id=cliente class=di.Cliente/> </beans>

A tag import possui o atributo obrigatrio resource, que define qual arquivo dever ser importado para a configurao do Spring. Os caminhos dos arquivos a serem importados sempre so relativos ao do arquivo que est fazendo a importao. Sendo assim, se o arquivo da listagem 6 estivesse, dentro do classpath do sistema no diretrio di/recursos o arquivo importado servicos.xml tambm estaria neste mesmo diretrio e daos.xml se encontraria no path di/recursos/dao. O outro modo de obter o mesmo resultado usando um construtor especial oferecido tanto por ClassPathXmlApplicationContext quanto FileSystemApplicationContext que recebe como parmetros um array de strings fornecendo os caminhos para os arquivos de configurao a serem usados. A listagem 7 exemplifica este processo usando a classe ClassPathXmlApplicationContext.
Listagem 7 Modularizando a configurao com o construtor especial
String[] arquivos = {di/recursos/spring.xml, di/recursos/servisos.xml, di/recursos/dao/daos.xml}; ApplicationContext contextoSpring = new ClassPathXmlApplicationContext(arquivos);

Dentre as duas opes a princpio mais interessante a primeira, visto que no necessrio recompilar o cdigo fonte caso seja necessrio adicionar algum novo arquivo de configurao ao container. No entanto, a segunda opo se mostra interessante em situaes nas quais a escolha dos arquivos de configurao envolvam alguma lgica interna do seu sistema.

Escopo Singleton vs Prototype Por padro todo bean gerenciado pelo Spring possui escopo singleton. fundamental compreender a diferena entre os dois escopos bsicos oferecidos pelo Spring para evitarmos problemas no futuro. Tal como exposto na tabela 1, quando um bean se encontra no escopo singleton o Spring se encarregar de manter uma nica instncia deste bean sobre seu controle. Sendo assim, toda vez que estivermos chamando o bean cliente definido na listagem 2 estaremos obtendo a mesma instncia da classe di.Cliente. No entanto, importante observar que estamos lidando aqui com um singleton relativo, visto que nada impede que criemos fora do container uma instncia diferente desta mesma classe chamando seu construtor padro, por exemplo. Um fator que precisa ser levado em conta que o BeanFactory e o ApplicationContext adotam polticas diferentes com relao a beans com escopo singleton. Quando o ApplicationContext inicializado, por padro todos os beans com escopo singleton so instanciados e possuem suas dependncias injetadas, ao passo que no BeanFactory estes s sero preparados no momento em que forem chamados pela primeira vez. J no caso do prototype, sempre que pedirmos ao container um bean que pertena a este escopo obteremos uma nova instncia. Isto nos trs um certo impacto na performance, visto que sempre ocorrer o processo de preparao do bean, que composto por duas etapas: instanciao do mesmo e injeo das dependncias. Na prtica utiliza-se o padro singleton para beans mais complexos e que no armazenem estado, como por exemplo a classe SessionFactory do Hibernate. Uma situao para a qual necessrio ficar atento quando um bean com escopo singleton possui uma dependncia com escopo prototype. preciso ter conscincia de

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

que a injeo de dependncias em um bean s feita no momento em que o bean instanciado. Sendo assim, a dependncia com escopo prototype injetada no bean singleton apenas uma vez. Se voc quiser no entanto que o seu bean com escopo singleton sempre obtenha uma nova instncia de sua dependncia com escopo prototype, uma soluo tornar este bean consciente da existncia do container de injeo de dependncias. Esta no uma boa prtica pois estamos adicionando peso ao Spring, visto que agora uma classe de negcios da nossa aplicao passa a possuir uma dependncia direta com o container de injeo de dependncias. Mas caso seja de fato necessrio, basta que sua classe implemente a interface org.springframework.context.ApplicationContextAware tal como a verso alternativa da classe Cliente que encontra-se exposta na listagem 8.
Listagem 8: um bean com conscincia do container de injeo de dependncias
public class Cliente implements ApplicationContextAware { // o restante da classe igual private ApplicationContext applicationContext; public ApplicationContext getContextoSpring() { return applicationContext; } public void setApplicationContext(ApplicationContext ac) throws BeansException this.applicationContext = ac; } } {

O container do Spring ir injetar nas classes que implementem a interface ApplicationContextAware uma instncia de si mesmo chamando o mtodo setApplicationContext, que recebe como parmetro uma instncia e ApplicationContext. Sendo assim, internamente a classe pode pedir ao container que sempre lhe retorne uma nova instncia de uma de suas dependncias cujo escopo seja singleton. Inicializao tardia de beans singleton Tal como falamos na seo anterior, o ApplicationContext por default prepara todos os beans com escopo singleton no momento em que carregado. Tal comportamento nem sempre adequado, visto que h situaes nas quais alguns beans so usados somente em circunstncias muito especficas. Sendo assim, porque carreg-los se talvez nem sejam necessrios durante a execuo do sistema? A soluo para o problema simples. Basta adicionarmos o atributo lazy-init tag bean com o valor true. Agora o bean s ser processado no momento em que for requerido pela primeira vez. possvel incluir o atributo lazy-init na tag bean tambm: assim altera-se o comportamento default de carregamento para todos os beans presentes naquele arquivo de configurao. No entanto, nem sempre esta uma boa prtica. Enquanto o sistema estiver em desenvolvimento, interessante que todos os beans sejam carregados, visto que assim ser possvel encontrar erros de configurao nesta etapa inicial do processo, facilitando assim a correo de erros. Autowiring O container de injeo de dependncias do Spring pode automaticamente descobrir quais as dependncias de um bean a partir de um recurso bastante interessante chamado autowiring. Como vantagem, o desenvolvedor pode reduzir significativamente o nmero de propriedades e construtores que precisa especificar em seus arquivos de configurao.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

O funcionamento do autowiring inicia-se quando marcamos um bean para que seja auto injetado8 pelo container. Quando este bean for ser iniciado, o container ir varrer todos os atributos presentes em sua classe e, para cada um, verificar entre as definies de beans armazenada em seu interior a existncia de um bean que possa ser injetado naquele ponto. Encontrados todos os candidatos apropriados, estes so injetados no bean. Caso haja alguma ambigidade, o container no saber qual bean deve ser injetado e, neste caso, uma exceo do tipo org.springframework.beans.factory.NoSuchBeanDefinitionException informando qual atributo no pode ser injetado. A melhor maneira de entender este conceito v-lo em prtica. Na listagem 9 podemos ver como configurar o Spring para tirar proveito deste recurso. Podemos ver trs beans definidos: daoLivro, cliente e autowired. O primeiro ser injetado nos demais. Enquanto na definio do bean cliente precisamos definir todas as dependncias manualmente, o mesmo no verdade com o bean autowired. Repare que no foi necessrio incluir em sua definio nenhum construtor ou propriedade, apenas o atributo autowire com o valor byType.
Listagem 9 Usando autowiring
<beans> <bean id="daoLivro" class="di.DAOLivroTexto"> <property name="arquivo" value="/livros.txt"/> </bean> <bean id="cliente" class="di.Cliente"> <property name="daoLivro" ref="daoLivro"/> </bean> <bean name="autowired" class="di.Cliente" autowire="byType"> </bean> </beans>

Quando lidamos com este recurso, nosso principal oponente a ambigidade. Se na listagem 9 houvesse mais um bean do tipo di.DAOLivroTexto nos depararamos com um erro no momento em que o bean autowired fosse iniciado pelo container, pois este no saberia qual bean injetar na propriedade daoLivro do bean autowired. Uma das ferramentas que possumos para evitar estes problemas so os modos fornecidos pelo Spring para encontrar automaticamente as dependncias a serem injetadas. Na tabela 2 podemos ver todos estes modos, cujos nomes correspondem ao valor a ser digitado no atributo autowire de um bean automaticamente injetado.
Tabela 2 - Estratgias de auto injeo de dependncias

Modo no byName

byType

constructor

Descrio Comportamento default. Desabilita a auto injeo de dependncias para o bean. O container ir buscar por dependncias que possuam o mesmo nome que a propriedade a ser injetada. Sendo assim, na listagem 9 poderamos ter definido a auto injeo usando esta estratgia que funcionaria sem problemas. Caso no hajam beans com o mesmo nome presentes entre as definies do container, a exceo NoSuchBeanDefinitionException. A busca por dependncias ser por tipo. O container ir buscar por beans que sejam do mesmo tipo que a dependncia a ser injetada. Havendo mais de uma possibilidade ser disparada uma exceo do tipo NoSuchBeanDefinitionException. anloga estratgia byType. A Diferena que ser feita a injeo de dependncias a partir dos construtores do bean.

O termo em ingls que poderia ser adotado ao invs de auto injetado seria autowired

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

autodetect

Seguindo esta estratgia o container ir primeiro buscar executar a injeo de dependncias por construtor. Se for encontrado um construtor default no bean, o container passar a adotar a estratgia byType.

Deve-se usar a auto injeo de dependncias apenas em projetos de pequeno e mdio porte, visto que trata-se de um processo bem menos preciso que a injeo explcita atravs da definio de propriedades e construtores. Apesar do Spring se esforar ao mximo para fazer a escolha correta, podem haver situaes nas quais uma injeo incorreta seja feita. Sendo assim seu uso normalmente desencorajado em projetos maiores, a no ser que sejam adotadas regras rgidas na nomenclatura dos beans e sua tipagem. Caso queira diminuir ainda mais a quantidade de configurao a ser digitada, possvel definir o comportamento de auto injeo default do container adicionando o atributo default-autowire tag beans com um dos valores presentes na tabela 2. Assim todos os beans nela contidos seguiro a mesma poltica. Para aumentar a preciso da injeo automtica, podemos tambm excluir candidatos injeo incluindo o atributo autowire-candidate com o valor false na tag bean do componente que queremos remover do processo de busca. Outra possibilidade interessante dar preferncia a uma dependncia especfica adicionando o atributo primary com valo true tag bean correspondente. Em situaes nas quais ocorram mais de uma possibilidade de escolha, este ser privilegiado no processo, ajudando assim a diminuir a possibilidade de ambigidade no processo de auto injeo de dependncias. Porm, estas duas alternativas acabam por tornar mais complexo o processo de criao dos arquivos de configurao. Por esta razo uma boa prtica simplesmente no usar o autowiring em projetos de grande porte.

Callbacks de Ciclo de Vida H situaes nas quais no basta apenas injetar as dependncias de um bean e definir seu escopo. So casos nos quais para que um bean esteja pronto para uso, seja necessrio algum pr-processamento interno antes que o mesmo seja fornecido ao objeto que o solicitou ao container. Alm disto, h momentos nos quais necessrio que o prprio bean libere os recursos que usou durante sua existncia. Spring nos oferece dois eventos que podemos customizar no ciclo de vida de nossos beans: inicializao, que executado logo aps todas as dependncias de um bean terem sido injetadas e destruio, executado apenas aps o container que gerencia o bean ter sido destrudo. O callback de inicializao pode ser adicionado ao bean de duas maneiras. A primeira delas a implementao da interface org.springframework.beans.factory.InitializingBean. Esta contm um nico mtodo do tipo chamado afterPropertiesSet() que dispara uma exceo genrica. Na listagem 10 h um exemplo de sua implementao. Este procedimento no recomendado pois acopla o bean ao Spring Framework, violando assim um dos principais objetivos do framework que justamente sua no intruso nas classes do sistema.
Listagem 10 Implementando callbacks de inicializao e destruio no cdigo fonte
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class ClienteCallbacks implements InitializingBean, DisposableBean { public void afterPropertiesSet() throws Exception { System.out.println("Todas as dependncias injetadas"); }

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

public void destroy() throws Exception { System.out.println("Container destruido"); } }

A outra opo incluir na tag bean o atributo init-method. O valor do atributo deve ser o nome de um mtodo definido no bean que no possua atributos e que pode ou no disparar alguma exceo. Esta a abordagem adequada, visto que assim garantimos que nosso bean no esteja diretamente acoplado ao Spring Framework. J o callback de destruio tambm pode ser adicionado usando basicamente os mesmos procedimentos que adotamos par ao callback de inicializao. Podemos implementar a interface DisposableBean, que nos obrigar a implementar o mtodo destroy(), tal como fizemos na listagem 10 ou, se preferirmos, podemos tambm adicionar o atributo destroy-method tag bean correspondente. O valor do deste atributo dever ser um mtodo que no possua parmetros. Como no caso do callback de inicializao, esta a abordagem favorita por evitar o acoplamento de nossas classes ao cdigo do Spring Framework. H um detalhe que precisa ser mencionado: o callback de destruio no executado jamais em beans cujo escopo seja prototype, pois uma vez criado, este bean no est mais sobre o poder do container de injeo de dependncias, sendo assim impossvel que o container venha a executar os mtodos de destruio nestes beans.

Uma alternativa ao XML que apareceu pela primeira vez no Spring 2.0 o uso das anotaes. Trata-se de um caminho bastante interessante para os que gostam de ver suas configuraes prximas ao cdigo fonte ou sentem-se incomodados com a necessidade de se escrever documentos XML. O problema com as anotaes que elas aumentam o peso do Spring ao acoplar nossas classes ao Spring Framework. Como veremos, possvel diminuir este acoplamento ao adotarmos anotaes baseadas em JSRs, porm mesmo assim estaremos aumentando o acoplamento de nossas classes, o que no ocorreria se estivssemos adotando configuraes puramente baseadas em XML. Outro problema que a necessidade de se recompilar cdigo ao adicionarmos novos componentes ao nosso sistema aumenta significativamente. Porm as anotaes no excluem completamente o XML. Na realidade, XML e anotaes convivem perfeitamente bem em um mesmo sistema. Voltando ao nosso sistema inicial, uma verso alternativa baseada em anotaes precisaria de um arquivo de configurao tal como o exposto na listagem 11.

Alimentando o Container com Anotaes

Listagem 11 Configurando o container para trabalhar com anotaes


<?xml version="1.0" encoding="ISO-8859-1"?> <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.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:annotation-config/> <context:component-scan base-package="di.anotados"/> <bean id="daoLivro" class="di.DAOLivroTexto" scope="prototype" primary="true"> <property name="arquivo" value="/livros.txt"/> </bean> </beans>

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Como pode ser observado na listagem 11, ainda estou mapeando um bean usando XML. Foi feito propositalmente para expor como as duas abordagens, anotaes e XML convencional convivem perfeitamente lado a lado. Comparando a listagem 11 com a listagem 2 observa-se a incluso de um novo namespace: context. fundamental que este seja declarado para que o Spring possa trabalhar com anotaes. H tambm duas novas tags: <context:annotation-config/> informa o container que sero usadas configuraes baseadas em anotaes alm do XML convencional. Outra tag importante <context:component-scan/>. Esta instrui o container a, no momento em que for inicializado, varrer todas as classes contidas no pacote di.anotados em busca dos beans a serem gerenciados pelo container. O leitor atento tambm observar a ausncia do bean cliente. Nesta verso alternativa do nosso sistema este bean ser configurado usando apenas anotaes. Sendo assim, implementamos uma classe chamada ClienteComponente exposta na listagem 12. Esta classe expe praticamente todas as configuraes que expusemos na seo dedicada configurao baseada em XML. Dado que os conceitos bsicos da injeo de dependncias foi dado na seo em que tratamos da configurao proveniente de documentos em formato XML, nosso foco agora ser em expor os equivalentes daquela configurao ao adotarmos o modelo de configuraes baseadas em anotaes.
Listagem 12 A classe ClienteComponente
import import import import import import di.IDAOLivro; javax.annotation.PostConstruct; javax.annotation.PreDestroy; javax.annotation.Resource; org.springframework.context.annotation.Scope; org.springframework.stereotype.Component;

@Scope("prototype") @Component("clienteAnotado") public class ClienteComponente {

private IDAOLivro daoLivro; public IDAOLivro getDaoLivro() { return this.daoLivro; } @Resource(name="daoLivro") public void setDaoLivro(IDAOLivro dao) { this.daoLivro = dao; } @PostConstruct public void init() { System.out.println("Fui construido. E meu dao " + getDaoLivro().getClass()); } @PreDestroy public void destroy() { System.out.println("Meu container foi destruido"); } }

Identificando beans com @Component Ao varrer o pacote di.anotados o container ir buscar todas as classes que possuam a anotao @Component. Esta equivale tag bean que vimos anteriormente. Como boa prtica, interessante passar como parmetro para esta classe um valor do tipo string que nomeie nosso bean. Caso no seja feito, o container ir criar um nome interno para o bean, porm este seria de pouca valia para ns, pois um bean realmente til aquele que possamos usar, e para us-lo, este precisa ser nomeado. Pense nesta anotao como a dica que enviamos ao container para que identifique uma de nossas classes como um bean a ser gerenciado.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Definindo o escopo com @Scope A anotao @Scope o equivalente ao atributo scope da tag bean. Se omitido, ser adotado o escopo padro do Spring que, tal como j mencionado, o Singleton. Esta anotao recebe como parmetro o nome do escopo que iremos adotar. Na listagem 12 s para variar adotamos o escopo prototype. Definindo dependncias com @Resource Anotaes tambm possuem um relativo para a tag property. No caso, estamos falando da anotao @Resource, que deve ser aplicada sobre atributos ou setters de nossas classes. Este atributo recebe como parmetro o nome do bean que desejamos seja injetado em nosso bean. interessante observar que esta anotao no nativa do Spring, mas sim da JSR250, cujo objetivo definir anotaes para conceitos semnticos em comum presentes nas plataformas Java SE e EE. Sendo assim, ao usarmos esta anotao, estamos na realidade evitando mais uma ligao direta com classes do Spring, o que uma prtica interessante, visto que no futuro, caso seja necessrio trocar o container de injeo de dependncias esta tarefa se tornar menos trabalhosa. Na listagem 12 estamos instruindo o container a injetar o bean daoLivro no bean clienteAnotado. Autowiring com @Autowired ou @Inject Equivalente ao atributo autowired que vimos na configurao baseada em XML possumos as anotaes @Autowired e @Inject. @Autowired a anotao provida pelo Spring. Sendo assim, ao adot-la devemos ter em mente que estamos incluindo uma dependncia direta ao Spring Framework em nosso cdigo fonte. J a anotao @Inject faz parte da JSR-330, que especifica o mecanismo de injeo de dependncia padro para a plataforma Java. Sendo assim, o uso de @Inject prefervel ao de @Autowired, pois assim estamos criando uma dependncia com um padro Java, e no algo to especfico quanto o Spring. Na listagem 13 podemos ver um exemplo da aplicao de @Autowired em mais uma verso de nosso bean cliente, assim possvel expor mais uma diferena entre @AutoWired e @Inject. No caso, @Autowired possui um atributo adicional chamado required, que aceita um valor booleano. Quando definido como true, caso no seja encontrado o bean a ser injetado, uma exceo ser disparada pelo container de injeo de dependncias. Esta opo til quando a aplicao est em desenvolvimento, pois permite aos desenvolvedores encontrar problemas antes que o sistema entre em produo.
Listagem 13 Usando @Autowired
import di.IDAOLivro; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component("clienteAnotadoAutowired") public class ClienteComponenteAutoWired { @Autowired(required=true) private IDAOLivro dao; public IDAOLivro getDaoLivro() {return dao;} public void setDaoLivro(IDAOLivro dao) {this.dao = dao;} }

Callbacks de inicializao e destruio com @PostConstruct e @PreDestroy

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Na listagem 12 podemos ver a aplicao das anotaes @PostConstruct e @PreDestroy, que equivalem aos atributos init-method e destroy-method que vimos na configurao baseada em XML. Seu uso no poderia ser mais simples: inclua @PostConstruct no mtodo sem parmetros que dever ser executado aps ter sido feita a injeo de dependncias em seu bean para identificar o callback de inicializao e @PreDestroy no mtodo sem parmetros que dever ser executado no momento em que o container de injeo de dependncias for ser destrudo. Quando o XML anula as anotaes Ao ser inicializado, o container do Spring primeiro carrega as configuraes provenientes de anotaes para em seguida processar as configuraes em formato XML. Sendo assim, importante que o leitor saiba que, caso um bean seja configurado inicialmente usando anotaes, e este mesmo bean esteja especificado no formato XML, as configuraes no segundo formato anularo a primeira. Este um erro muito comum em times que tenham optado por trabalhar com os dois formatos, porm pode ser visto tambm como uma alternativa vivel quando se deseja anular configuraes em cima das quais no possumos controle, como por exemplo as que esto presentes em classes j compiladas presentes no classpath de nosso sistema.

Limitaes das anotaes Atualmente configuraes baseadas em anotaes no permitem que seja mapeado mais de um bean para uma mesma classe tal como fizemos na listagem 4. Caso seja necessrio que isto seja feito, o desenvolvedor possui apenas duas alternativas: ou mapeia apenas um bean usando anotaes para uma classe e o restante usando XML ou faz todo o trabalho usando apenas XML. Dentre as duas alternativas, a segunda uma melhor prtica, visto que assim expe para o time todas as variantes do bean para todos os membros da equipe de uma forma mais explcita, evitando assim problemas de comunicao dentro do time. Outra limitao das anotaes que elas no nos permitem definir o valor de atributos primitivos ou listas, tal como podemos fazer facilmente no caso do XML.

Configurao baseada em Java (100% livre de XML!)


No Spring 3.0 foi introduzido um novo tipo de contexto de aplicao chamado AnnotationConfigApplicationContext que, pela primeira vez, possibilita ao desenvolvedor configurar um container de injeo de dependncias do Spring sem a presena de qualquer arquivo XML, pois toda configurao feita via cdigo. Trata-se de uma alternativa bastante poderosa que pode ser usada em situaes nas quais os beans gerenciados pelo container no possam ser definidos apenas declarativamente como fizemos usando apenas anotaes ou XML. Agora podemos incluir lgica neste processo de uma maneira bastante simples. Visto que todos os conceitos referentes ao processo de gerenciamento de beans j foi tratado nas sees anteriores deste artigo, iremos ver aqui apenas como mapear os beans usando este novo recurso de uma maneira rpida comparando-o com as maneiras anteriores.

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

Apresentando @Configuration e @Bean Antes de tratarmos da classe AnnotationConfigApplicationContext iremos ver o que o alimenta, no caso, as anotaes @Configuration e @Bean aplicadas a POJOs. Na listagem 14 podemos ver a aplicao destas anotaes.
Listagem 14 Aplicando as anotaes @Configuration e @Bean
import import import import import import import di.Cliente; di.DAOLivroSGBD; di.DAOLivroTexto; di.IDAOLivro; org.springframework.beans.factory.annotation.Autowire; org.springframework.context.annotation.Bean; org.springframework.context.annotation.Configuration;

@Configuration public class BeanSource { @Bean(name="daoLivro") public IDAOLivro getDAOLivro() { return new DAOLivroTexto(); } @Bean(name="cliente") public Cliente getCliente() { Cliente saida = new Cliente(); saida.setDaoLivro(getDAOLivro()); return saida; } @Bean(name="clienteSGBD") public Cliente getClienteSGBD() { Cliente saida = new Cliente(); saida.setDaoLivro(new DAOLivroSGBD()); return saida; } @Bean(name="clienteAutowired", autowire=Autowire.BY_TYPE) public Cliente getClienteAutowired() { return new Cliente(); } }

Tabela 3 - Atributos de @Bean

Atributo name autowire

initMethod destroyMethod

Descrio O nome dado ao bean que ser retornado Qual poltica de autowiring que ser adotada pelo container. Valores possveis: Autowire.BY_TYPE Autowire.BY_NAME Autowire.NO > Desabilita o autowiring, e o valor default Nome do mtodo que dever ser invocado no bean aps este ter suas dependncias injetadas Nome do mtodo que dever ser invocado quando o container que gerencia o bean for destrudo

A classe presente na listagem 14 o que chamamos de Configuration, ou seja, uma classe anotada com @Configuration e que possui funes anotadas com a anotao @Bean que produzem beans que sero gerenciados pelo container de injeo de dependncias do Spring. Sendo assim, para criar uma classe de configurao, tudo o que o desenvolvedor precisa fazer anot-la com @Configuration e em seguida implementar uma ou mais funes anotadas com @Bean, cujos atributos encontram-se listados na tabela 3. Autowiring

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

A primeira impresso que temos quando nos deparamos com este novo recurso que no precisaremos mais da injeo automtica de dependncias, visto que estamos manualmente criando nossos beans. Felizmente isto no verdade. Para ativar o autowiring, basta definir o valor do parmetro autowire com o valor Autowire.BY_NAME ou Autowire.BY_TYPE tal como exposto na tabela 3. Observando a listagem 14 vemos que o autowiring aplicado no mtodo getClienteAutowired() usando a estratgia por tipo. Definindo o escopo Novamente aqui o padro do Spring se aplica. Se no for definido explicitamente qual o escopo do bean, este ser interpretado como pertencente ao escopo singleton. Para que o bean possua um escopo

Callbacks de Inicializao e Destruio Tal como na configurao baseada em XML como na configurao baseada em anotaes, tambm podemos definir os callbacks de inicializao e destruio. A diferena que os definimos com os atributos initMethod e destroyMethod presentes na anotao @Bean. Exatamente como nos casos anteriores, eles devem conter o nome de um mtodo que no possua atributos presentes na classe do bean a ser retornado. Apresentando o container AnnotationConfigApplicationContext A classe que possibilita a configurao baseada em Java AnnotationConfigApplicationContext, que se encontra no pacote org.springframework.context.annotation. Para us-la, no entanto, necessrio adicionar duas dependncias externas ao seu projeto. No caso as bibliotecas CGLIB e ASM9, que so usadas para manipular bytecode em tempo de execuo. H dois modos de se alimentar as configuraes de AnnotationConfigApplicationContext. O desenvolvedor pode criar uma nova instncia desta classe passando uma nica classe de configurao ou um array de classes de configurao ou programaticamente. As duas maneiras podem ser vistas na listagem 15.
Listagem 15 Alimentando AnnotationConfigApplicationContext
AnnotationConfigApplicationContext contexto = null; // Alimentando com uma nica classe de configurao contexto = new AnnotationConfigApplicationContext(BeanSource.class); //Alimentando com um array de classes de configurao contexto = new AnnotationConfigApplicationContext({BeanSource.class, DataSources.class}); // Alimentando o context programticamente contexto = new AnnotationConfigApplicationContext(); contexto.register(BeanSource.class); //aps adicionar todas as classes ao contexto, execute obrigatriamente o mtodo refresh() contexto.refresh();

Concluses
Como pudemos ver, o container de injeo do Spring uma ferramenta bastante rica, que nos permite resolver de maneira elegante o problema do alto acoplamento em nossos sistemas. Tal como dito na introduo, importante conhecer o conceito de
A biblioteca CGLIB (Code Generation Library) pode ser obtida em seu site oficial: http://cglib.sourceforge.net/ Para este artigo foi usada a verso 2.2. J a biblioteca ASM pode ser obtida em http://asm.ow2.org/. Usamos neste artigo a verso 3.2.
9

Guia itexto: Injeo de Dependncias com Spring Framework 3 http://devkico.itexto.com.br

injeo de dependncias mesmo que o Spring jamais seja usado, porque seu conhecimento torna explicita a principal causa de designs ruins de aplicao. Porm, caso o Spring venha a ser adotado, importante que a sua no intruso seja mantida o mximo possvel, pois caso contrrio podemos acabar voltando ao problema do alto acoplamento. Tal como exposto no artigo, conseguimos manter esta leveza a partir da adoo de configurao no formato XML ou Java e, no caso das anotaes, adotando ao mximo possvel apenas anotaes que sejam parte de alguma JSR, ao contrrio das que fazem parte do core do Spring. O mais interessante, no entanto, a constatao do poder que o conceito de injeo de dependncias possui. Percebemos este poder ao constatar que apenas o que foi exposto neste artigo fornece a base para todos os demais componentes do Spring Framework e seus derivados, como Grails por exemplo.

http://www.springframework.org Site oficial do Spring Framework http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/ Documentao de referncia do Spring Framework 3.0 http://www.objectmentor.com/publications/dip.pdf - Artigo The Dependency Injection Principle de Robert C. Martin http://www.martinfowler.com/articles/injection.html - Artigo Inversion of Control Containers and the Dependency Injection pattern de Martin Fowler que cunhou o termo Injeo de Dependncias

Referncias

Henrique Lobo Weissmann (o Kico) (kicolobo@itexto.net) consultor Groovy/Grails, fundador do Grails Brasil e scio da itexto Desenvolvimento de Projetos (http://www.itexto.com.br), que atua na criao de projetos adotando software livre e muito Grails. Alm disto, em seu blog (http://devkico.itexto.com.br) expe sua experincia no desenvolvimento de software.

Você também pode gostar