• Nenhum resultado encontrado

Declarando beans

No documento Casa do Código. Prefácio (páginas 44-50)

Para que um bean exista são necessários três elementos: as configurações, o contai- ner e a classe que o implementa. No caso do Spring as configurações podem vir de três fontes: XML, anotações ou código Java. Nosso foco inicial será o primeiro for- mato, pois este torna explícito de uma maneira bastante didática o funcionamento do container. Como veremos no transcorrer deste capítulo, as fontes restantes tem como objetivo principal a redução do XML ou mesmo sua eliminação, o que aumenta bastante a produtividade do desenvolvedor.

3.3. Declarando beans Casa do Código A configurações devem nos fornecer os dados mínimos para que o container consiga instanciar e gerenciar o ciclo de vida de nossos beans. A única informa- ção que obrigatoriamente devemos fornecer é qual a classe que implementa o bean. Usamos a tag<bean>para declarar um bean e nesta o único atributo obrigatório é

class. Sendo assim, para declaramos uma implementação de nossa interface Fonte- Dados que obtenha nossos usuários usando um arquivo texto configuramos o bean tal como no exemplo abaixo:

<bean id="fonteDados" class="br.com.casadocodigo.FonteDadosArquivo"/> O atributo id, como o próprio nome já diz, identifica unicamente um bean no container. Caso o atributo não esteja presente, o bean seria instanciado e gerenciado pelo Spring da mesma maneira. A diferença no caso seria quem nomearia o bean: o próprio container. É interessante observar que um bean pode ter mais de um nome, mas não se preocupe com isto por enquanto, este tema será abordado mais à frente e só é de fato útil em projetos maiores que envolvam equipes muito grandes.

Se nosso bean já tem um nome, é fundamental definirmos também qual a sua origem, ou seja, qual classe o implementa. Para tal usamos o atributo class, o único obrigatório, aonde devemos fornecer o nome completo da classe.

Quando nosso container for instanciado e alimentado com estas configurações, o bean será instanciado e em seguida estará disponível para uso pelo restante do sistema.

No entanto nossa configuração ainda está incompleta. Definir quais objetos ins- tanciar é ótimo, porém o padrão de projeto factory já resolveria nosso problema. Neste momento nosso container ainda não passa de um factory configurável por XML, o que ainda não justifica a adoção do Spring. O leitor atento já deve ter obser- vado que a classe que estamos instanciando se chama FonteDadosArquivo. Que tal se também definíssemos qual o arquivo em que se encontram os dados que queremos instanciar? Entra em ação a tag<property>. Podemos definir qual objeto carregar modificando nossa configuração para que fique similar ao exemplo abaixo:

<bean id="fonteDados" class="br.com.casadocodigo.FonteDadosArquivo"> <property name="arquivo" value="/arquivos/pessoas.csv"/>

</bean>

Há dois atributos na tag<property>. Primeiro é necessário definir qual atributo de nosso objeto deverá ser modificado, o que é feito com o atributo name, que faz referência ao padrão JavaBean que deve, por convenção, ser adotado por todos os

nossos beans. De acordo com esta propriedade, deve haver implementado na classe FonteDadosArquivo um método chamado setArquivo que receba como parâmetro um objeto do tipo String. O valor a ser injetado encontra-se definido no atributo value. É interessante observar que não é necessário se preocupar com o tipo a ser recebido pelo setter, pois o tipo é descoberto em tempo de execução pelo container. Com base nesta configuração mais rica, o container irá executar a sequência de operações descrita abaixo:

1) Bean fonteDados do tipo br.com.casadocodigo.FonteDadosArquivo é instanciado 2) O valor da propriedade arquivo é definido como sendo igual a

“/arquivos/pessoas.csv”

3) Bean instanciado e configurado disponível para ser usado pelo resto do sistema É interessante observar que o bean só é disponibilizado para uso após seu es- tado ter sido inicializado. Como “brinde” acabamos de ganhar a solução para toda uma gama de problemas decorrentes da obtenção concorrente de objetos cuja ini- cialização do estado não foi totalmente concluída. E este sequer era nosso objetivo inicial!

No entanto isoladamente um bean não é de grande utilidade. O poder do contai- ner começa a surgir a partir do momento em que a injeção de dependências começa a entrar em ação. Podemos ver no código abaixo a configuração completa do nosso sistema tal como se encontra no estado atual.

<?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.xsd"> <bean id="fonteDados" class="br.com.casadocodigo.FonteDadosArquivo">

<property name="arquivo" value="/arquivos/pessoas.csv"/> </bean>

<bean id="impressor" class="br.com.casadocodigo.ImpressorImpl"/> <bean id="processador" class="br.com.casadocodigo.Processador">

<property name="impressor" ref="impressor"/> <property name="fonteDados" ref="fonteDados"/>

3.3. Declarando beans Casa do Código </bean>

</beans>

A primeira novidade que vemos no arquivo completo é a inclusão da tag<beans> que é o elemento raiz do documento. Não é necessário se intimidar com as declara- ções de namespaces presentes neste documento visto que atualmente a maior parte das IDEs, com seu suporte ao Spring já oferecem a possibilidade de gerar automati- camente este documento para os novatos no framework. Como veremos mais adi- ante, o Spring oferece uma série de namespaces que tornam a vida do desenvolvedor muito mais fácil ampliando a semântica do XML padrão.

Na versão completa de nossa configuração, devemos focar nossa atenção sobre o bean processador. Um novo atributo aparece na tag<property>: ref (abreviação de reference), cujo valor é o nome de um dos beans definidos na configuração. Esta é a tão falada injeção de dependências em ação. Novamente, é importante observar que não precisamos nos preocupar com o tipo dos objetos que estamos injetando pois o próprio container se encarrega desta tarefa. Caso haja algum problema com a tipagem dos objetos, o container irá disparar uma exceção nos informando do erro para que sejam feitas as alterações necessárias nas configurações e os beans se tornem disponíveis.

Novamente, no caso do bean processador, este só estará disponível após ter sido instanciado e todas as suas dependências terem sido instanciadas, preparadas e inje- tadas. É importante observar que nosso container já pode ser visto como uma classe factory melhor evoluída que não só decide quais classes instanciar e quais proprie- dades definir em tempo de execução, como também já inicia o processo de injeção de dependências. No transcorrer deste capítulo a distância entre o padrão factory e nosso container tenderá a crescer até chegarmos ao ponto que serão vistos como primos distantes.

Tipos de injeção

O Spring trabalha com dois tipos de injeção de dependências. A que expomos acima é chamada injeção por setter (setter injection). Como o próprio nome diz, as dependências são injetadas em nosso bean a partir de métodos setter que implemen- tamos em nossas classes. Nossa outra opção é a injeção por construtor constructor injection.

Para entender melhor a injeção por construtor, imagine que nossa classe Proces- sador possua um construtor tal como o abaixo:

public Processador(FonteDados fonteDados, Impressor impressor) { setFonteDados(fonteDados);

setImpressor(impressor); }

Para executar a injeção por construtor, entra em ação a tag<constructor-arg> que podemos ver em ação no exemplo abaixo:

<bean id="processador" class="br.com.casadocodigo.Processador"> <constructor-arg ref="fonteDados"/>

<constructor-arg ref="impressor"/> </bean>

Assim como a tag<property>,<constructor-arg>pode receber como atributo tantovaluequantoref. No exemplo acima, a ordem de digitação das tags importa. Repare que coincide com a ordem em que os parâmetros são passados ao construtor da classe. É importante mencionar que também é possível digitá-los fora da ordem, mas neste caso faz-se obrigatória a presença do atributoindexque deve receber um valor numérico que represente a ordem do parâmetro a partir do zero no construtor, tal como pode ser visto no exemplo abaixo:

<bean id="processador" class="br.com.casadocodigo.Processador"> <constructor-arg ref="impressor" index="1"/>

<constructor-arg ref="fonteDados" index="0"/> </bean>

Uma pergunta pertinente neste momento é a respeito da razão pela qual existem estas duas opções de injeção. Uma só não tornaria o aprendizado do framework mais simples? Talvez, mas com certeza também o tornaria bem mais limitado. Deve ser levado em consideração que um dos objetivos principais por trás do Spring é o reaproveitamento de código legado de modo que sua integração seja a mais leve possível. Por mais leve, como já mencionado, deve ser entendido com o mínimo possível de dependências com relação ao código fonte do próprio Spring.

Existe uma longa discussão a respeito de qual seria a melhor forma de injeção. Os mais puristas defendem a injeção por construtor como a melhor. O argumento é que ao definirmos em um construtor todas as dependências de uma classe torna- mos evidente quais atributos não devem em hipótese alguma ser alterados após a instanciação da classe. O problema desta abordagem é que conforme nosso código

3.3. Declarando beans Casa do Código se desenvolve e novos atributos são incluídos em nossas classes, o número de parâ- metros a ser passado para nossos construtores tende a crescer e, consequentemente, sua manutenção vai se tornando mais complicada.

Em prol da injeção por setter estão dois argumentos: a de que permite a modi- ficação das dependências injetadas após a instanciação da classe e também o fato de evitar problemas decorrentes de construtores com número excessivo de parâmetros. No final das contas, nem uma nem outra alternativa é a mais recomendada. Qual opção usar deve sempre ser uma decisão tomada com base no bom senso, e não apenas no que um guru ou outro afirma a respeito do assunto.

Nada impede também que usemos também uma solução mista envolvendo os dois tipos de injeção de dependências em um mesmo bean. A configuração abaixo é um exemplo disto:

<bean id="processador" class="br.com.casadocodigo.Processador"> <constructor-arg ref="fonteDados" index="0"/>

<constructor-arg index="1"> <null/>

</constructor-arg>

<property name="impressor" ref="impressor"/> </bean>

Neste exemplo reaproveitamos o mesmo construtor passando o valor null para o segundo argumento e injetando a dependência impressor via setter.

Dando nome aos beans

Assim como pessoas possuem apelidos, o mesmo podemos fazer com beans. Há dois atributos da tag<bean>que podemos usar para nomearmos nossos compo- nentes. O primeiro já conhecemos: trata-se deid. Usamos este atributo quando precisamos definir um nome único para nossos beans.

O novo atributo se chamaname, que é usado quando definimos mais de um nome para o mesmo bean. Neste atributo podemos inclusive incluir uma lista de nomes, que devem estar separados pelo caractere de espaço, ponto e vírgula ou vírgula. O código abaixo expõe um exemplo de uso destes atributos:

<!-- Um bean com dois nomes: um definido por id, outro por name --> <bean id="impressor" name="impressorArquivo"

class="br.com.casadocodigo.ImpressorImpl"/>

<bean name="impressor, impressorArquivo"

class="br.com.casadocodigo.ImpressorImpl"/>

A possibilidade de criar mais de um nome para o mesmo bean é um recurso pouco usado na maior parte dos projetos. Normalmente esta possibilidade é explo- rada em projetos maiores nos quais times distribuídos desenvolvem partes do sis- tema que serão integrados posteriormente. É uma maneira interessante de manter os padrões de nomenclatura adotados por times distribuídos. Se seu projeto não for tão grande assim simplesmente não faz mais sentido, além de ser bem mais produ- tivo adotar um padrão de nomes unificado.

Caso seu projeto não possua um padrão de nomenclatura, uma boa prática é usar o adotado e sugerido pela equipe da SpringSource. Esta sugere que beans sigam o padrão camel cased, no qual o nome sempre é inicialmente digitado em letras minús- culas. Caso o nome seja composto, cada palavra é separada digitando seu primeiro caractere em letra maiúscula, tal como nestes exemplos: importador, importadorAr- quivo, importadorBancoDeDados.

No documento Casa do Código. Prefácio (páginas 44-50)