Vire o jogo com Spring framework

Vire o jogo com Spring framework

(Parte 1 de 5)

Casa do Código

Prefácio

Neste livro trataremos do Spring, um framework usado no desenvolvimento de aplicações corporativas baseado nos conceitos de inversão de controle, injeção de dependências e AOP. São palavras que muitas vezes soam alienígenas e muitas vezes não adquirem significado na mente do desenvolvedor. Este livro possui dois objetivos: clarificarosignificadoportrásdestesconceitoseexporcomosuaaplicaçãoacabapor gerar sistemas de qualidade superior, mais fáceis de manter e que, com isto, acabam por aumentar o valor agregado do nosso trabalho.

Mais que um framework para desenvolvimento de aplicações corporativas, vejo oSpringcomoumaferramentadisciplinadora. Conformeodesenvolvedorvaisehabituando ao seu modo de trabalho começa a valorizar ainda mais qualidades como uma melhor modularização do sistema, escrita de código mais simples, reaproveitamento de código legado e tecnologias já existentes, além da criação de interfaces mais significativas. No Spring podemos ver de forma nítida o núcleo da arquitetura de sistemas que é justamente o modo como componentes de software interagem entre si de uma maneira explícita. Para os que anseiam trilhar este caminho, é também um auxílio em sua formação.

O livro é dividido em duas partes. Na primeira tratamos dos conceitos em que se baseia o Spring. Veremos o que motivou sua criação, o que o framework trouxe de ganho para o desenvolvimento de aplicações corporativas e como são aplicados no núcleo do Spring que é seu container de inversão de controle/injeção de dependências. Com isto é fornecida ao leitor uma base sólida que pode ser aplicada tanto dentro quanto fora do contexto do Spring.

Na segunda parte temos uma abordagem mais mão na massa. Veremos aplicações do framework em situações reais do dia a dia, como por exemplo na camada de persistência, controle transacional, segurança e também criaremos uma aplicação web real baseada no Spring MVC. A grosso modo, pode-se dizer que quando escrevi a primeira parte do livro incluí o conteúdo que gostaria muito de ter aprendido na

Casa do Código faculdade,enquantonasegundaestãoasinformaçõesqueteriammepoupadomuito tempo no meu cotidiano como desenvolvedor.

A quem se destina

Este livro se destina a todos aqueles que já possuem algum conhecimento da plataforma Java, que já terão uma bagagem mais rica para entender o que tento explicar neste texto. Caso não seja o seu caso, tudo bem: os três primeiros capítulos contém o conceitual que você poderá aplicar em práticamente qualquer plataforma.

Agradecimentos

Agradeço à confiança e ao apoio (isto sem mencionar a paciência!) dos meus editores Paulo Silveira e Adriano Almeida sem os quais este livro não seria possível. Claro que eles não agiram sozinhos, Nanna - minha esposa - é fundamental por ter conseguido me aguentar neste processo de tradução do Springolês para o Português. Também preciso agradecer aos meus colegas, em especial ao Matheus Eduardo Moreira e o Felipe Zampa.

Os leitores tiveram participação extremamente importante: após o lançamento da versão beta fiquei maravilhado com a quantidade de pessoas interessadas neste material, o que me motivou a concluí-lo mais rápido e com a melhor qualidade possível. Alguns entraram em contato direto comigo com dicas e sugestões, e a estes ofereço meu agradecimento especial: Renan Reis, Rodrigo Monteiro, Adriano Faria Alves e Willardy Tyrone de Oliveira. E ei, também não posso deixar de agradecer ao apoio do Rodrigo Fernandes Moreira e Gabriela Corrêa da Eteg. Finalmente, para evitar que eu sofra consequências imprevisíveis, à minha mãe, Selma Weissmann. Infelizmente o espaço deste prefácio é limitado para conter todas as pessoas a quem devo agradecer, assim como minha memória. Caso seu nome me tenha escapado, por favor desculpe este mal agradecido: com certeza encontrarei alguma forma de retribuí-lo no futuro ok?

Muito obrigado a todos vocês.

Casa do Código Sumário

Sumário

Os conceitos por trás do Spring 1

1.1 Problema essencial: acoplamento4
1.2 A famigerada inversão10

1 Lide com o alto acoplamento de forma elegante 3

2.1 Por que criaram o Spring?15
2.2 O Mundo dos objetos em 200416
2.3 Os problemas do EJB em 200418
2.4 Alternativas começam a surgir: IoC/DI e AOP19
2.5 Container: o sujeito que torna tudo isto possível2
2.6 Do início ao fim de um objeto, entenda o ciclo de vida2
2.7 Spring em partes27
2.8 O Container28
2.9 Trabalhando com AOP e Aspects29
2.10 Instrumentação de código29
2.1 Acesso a dados e integração30
2.12 Aplicações na Web com o Spring30
2.13 E ainda mais componentes!31
2.14 Resumindo31

2 Conheça o Spring Framework 15

3.1 Preparando seu ambiente de desenvolvimento34
3.2 Nosso sistema de exemplo37
3.3 Declarando beans37

3 Conhecendo o Container 3 i

3.4 Instanciação por factory method43
3.5 Mapeando atributos complexos46
3.6 Usando o container49
3.7 O ciclo de vida do container52
3.8 Escopos53
3.9 Instanciação tardia57
3.10 Aproveitando o ciclo de vida dos beans58
3.1 Quando o bean conhece seu container61
3.12 Modularizando a configuração63
3.13 Aplicando herança na definição dos beans64
3.14 Spring Expression Language (SpEL)65
3.15 Resumindo70

Sumário Casa do Código

4.1 Autowiring: automatizando a injeção de dependências71
4.2 Vantagens e limitações da injeção automática76
4.3 Facilitando ainda mais com Anotações7
4.4 Configuração programática com Java86
4.5 XML, anotações ou configuração programática?93

4 Minimizando o XML com autowiring, anotações e Java 71

5.1 Como identificar os interesses transversais96
5.2 Entendendo AOP98
5.3 Preparando o ambiente de desenvolvimento100
5.4 A implementação do primeiro aspecto102
5.5 Entenda os advices103
5.6 Use os around advices104
5.7 Use o advice before106
5.8 E onde entra o Proxy nessa história?108
5.9 Entenda a execução110
5.10 Um uso interessante para AOP: Log de erros1
5.1 Declare aspectos com anotações AspectJ e esquemas XML12
5.12 A sintaxe AspectJ de declaração de point cuts116
5.13 Concluindo com um resumão conceitual121

5 AOP: adicionando novos comportamentos aos beans 95 iv

Casa do Código Sumário

Spring Framework na prática 123

6.1 Obtendo o código fonte126
6.2 Configure seu ambiente de desenvolvimento127
6.3 O que vêm por ai128

6 Colocando a mão na massa 125

7.1 A base para tudo: MVC132
7.2 Dispatcher Servlet: o maestro por trás do Spring MVC133
7.3 A preparação do projeto135
7.4 Como trabalhar com conteúdo estático140
7.5 Nosso primeiro controlador142
7.6 A definição da camada de visualização144
7.7 Trabalhe com redirecionamentos e sessão do usuário152
7.8 A definição do método de acesso153
7.9 Receba parâmetros de entrada154
7.10 Faça redirecionamentos154
7.1 Como lidar com a sessão do usuário e a classe ModelAndView155
7.12 O chato e repetitivo trabalho de criar formulários157
7.13 Ainda há mais de SpringMVC por vir161

7 Desenvolva aplicações web com Spring MVC 131

8.1 Faça a validação de formulários164
8.2 Envie seus avatares para o servidor com upload de arquivos168
8.3 Defina o corpo da resposta171
8.4 Faça requisições assíncronas com AJAX173
8.5 Concluindo com uma surpresa176

8 Ações recorrentes com o SpringMVC 163

9.1 DAO: no centro da mentalidade Spring180
9.2 Conecte-se ao banco de dados181
9.3 De volta ao DAO: o problema com as exceções186
9.4 Templates: acabe com o código repetido188
9.5 O trabalho com JDBC190

9 Acesso a dados 179 v

9.6 O trabalho com o Hibernate200
9.7 Integre com a JPA207
9.8 Concluindo211

Sumário Casa do Código

10.1 Entendendo as transações213
10.2 As políticas transacionais215
10.3 Preparando o ambiente de desenvolvimento219
10.4 Como o Spring implementa o suporte a transações219
10.5 Transações programáticas221
10.6 Declarando transações223
10.7 Concluindo225

10 Gerenciando transações 213

1.1 Entendendo autenticação e autorização228
1.2 Os módulos do Spring Security229
1.3 Configurando os filtros de acesso231
1.4 Configurando o contexto do Spring233
1.5 O formulário de login237
1.6 Escrevendo um provedor de autenticação2 39
1.7 Usando SpEL242
1.8 Protegendo invocação de métodos em beans243
1.9 Tags244
1.10 Conclusão245

1 Protegendo nossa aplicação com Spring Security 227 12 E ai, gostou? 247 Bibliografia 252

Parte I Os conceitos por trás do Spring

Capítulo 1 Lide com o alto acoplamento de forma elegante

Todo objeto é carente: e aí o problema começa.

Spring Framework é um framework voltado para o desenvolvimento de aplicações corporativas para a plataforma Java, baseado nos conceitos de inversão de controle e injeção de dependências. Esta é a descrição padrão que encontramos na grande maioria dos materiais sobre o assunto.

Vamos fazer diferente? Que tal não simplesmente descrever o funcionamento da ferramenta, massimapresentarosproblemasquemotivaramasuacriação? Sãoproblemas comuns no desenvolvimento de sistemas que ocorrem independentemente da plataforma e o Spring no final das contas é apenas uma ferramenta interessante para tratá-los.

Estas dificuldades podem ser agrupadas em duas categorias: essenciais e específicos da plataforma. Neste capítulo o objetivo é apresentá-las brevemente para, no transcorrer deste livro, entender como o Spring nos ajuda a minimizá-las.

1.1. Problema essencial: acoplamento Casa do Código

1.1 Problema essencial: acoplamento

Problemas essenciais são aqueles que independem da plataforma. Fred Brooks no seu texto clássico “No Silver Bullet” [2] aponta quatro dificuldades essenciais inerentes ao desenvolvimento de qualquer software:

• Conformidade: todo software precisa ser compatível com o ambiente no qual será executado. Isto inclui conformidade com sistema operacional, acesso a interfaces de sistemas legados e as próprias restrições físicas do ambiente.

• Invisibilidade: como podemos visualizar um software? Apesar dos avanços em notações como a UML ainda não chegamos a uma solução definitiva para este problema. Boa parte do nosso raciocínio se baseia em metáforas visuais que dificilmente se enquadram no desenvolvimento de projetos de software.

• Mutabilidade: os requisitos mudam constantemente e, com isto, faz-se necessário que a arquitetura de nossos sistemas seja projetada de tal forma que possa se adequar com o mínimo de impacto possível a estas transformações.

• Complexidade: provavelmente a pior das dificuldades, pois está diretamente relacionada aos limites do nosso intelecto. Conforme o software se desenvolve a complexidade das regras de negócio e das integrações que este precisa fazer evoluem até chegar a um ponto no qual os custos de manutenção se tornam proibitivos (o livro clássico de Fred Brooks, “The Mythical Man-Month” [1] pode ser resumido a esta questão).

A orientação a objetos quando bem aplicada consegue minimizar estes problemas essenciais através da metáfora do objeto. É uma ideia simples: se vivemos em um mundo rodeado de objetos interagindo entre si, por que não metaforizá-los em uma linguagem de programação que nos permita simular estas interações a fim de resolver problemas computacionais? Um plano perfeito no qual nada pode dar errado, não é? Claro que não.

Minimizamos o problema da conformidade a partir de interfaces bem definidas, com relação à invisibilidade, temos a UML, e a própria metáfora do objeto já é quase visual. Mutabilidade? Sempre podemos adicionar mais uma classe pra modificar algum comportamento, e com relação à complexidade, bem, agora temos classes e as coisas ficaram mais simples, certo? Não.

Se ignoramos o fato de que este relacionamento entre objetos não é simples, terminamos reféns de uma armadilha complexa da qual possivelmente a única saída

Casa do Código Capítulo 1. Lide com o alto acoplamento de forma elegante normalmente é a reescrita total do nosso código. Se já há complexidade no desenvolvimento procedural, com objetos em cena acabamos por adicionar também a complexidade inerente do gerenciamento de suas interações. Nosso plano perfeito falhou, e Robert C. Martin (aka “Uncle Bob”) em seu texto “The Dependency Inversion Principle” [10] aponta alguns sintomas de que nosso projeto pode estar apodrecendo. Estes são:

• Fragilidade: altere um trecho, veja diversos outros se partirem.

• Rigidez: consequência da fragilidade, o software é difícil de ser modificado.

Neste caso, tanto devido à sua fragilidade quanto por razões não técnicas. A própria gerência da empresa começaab arrar mudanças no sistema por estar traumatizada por um passado doloroso de bugs que surgem da solução de outros.

• Imobilidade: há componentes maravilhosos no software, que poderiam ser aproveitados em outros projetos. Infelizmente, sua remoção é tão custosa que ficamaisbaratosimplesmentereimplementarafuncionalidade(istosemmencionar que agora você tem de dar manutenção em mais de um lugar)

O que torna um projeto frágil, rígido e imóvel é a maneira como se encontra definida a interdependência entre seus componentes [10]. A solução para evitar estes sintomas é desenharmos nosso software de tal forma que consigamos gerenciar de maneira efetiva o modo como seus objetos se relacionam. Dizemos que um sistema possui alto acoplamento quando suas classes dependem muito umas das outras. Quanto mais uma classe sabe a respeito de outra, maior é o acoplamento entre as duas e, consequentemente, alterações em uma normalmente acarretam em mudanças de comportamento em locais inesperados do sistema.

Para expor o problema, vou iniciar com um exemplo bastante simples: uma integração. Nosso integrador é composto por basicamente três classes: um DAO que busca informações a partir de documentos no formato XML, o Integrador em si, que possui algoritmos fantásticos de otimização (o que o torna um candidato para reutilização) e um banco de dados relacional, que é o destino das informações que extraímos do nosso DAO (neste exemplo iremos ignorar classes de domínio a fim de manter a simplicidade).

1.1. Problema essencial: acoplamento Casa do Código

OqueéumDAO?

DAO significa Data Access Object. É uma estratégia de implementação que tem como objetivo separar a lógica de acesso a dados das regras de negócio de sua aplicação. Eis a ideia: escreva o código de acesso a dados em uma classe separada que implemente uma interface. Faça com que o resto do seu sistema tenha acesso direto apenas a esta interface. Precisou trocar a fonte de dados? Crie uma nova implementação desta interface e pronto: não precisa mais alterar sua classe cliente.

Como seu sistema saberá qual implementação usar? É o assunto deste livro!

Figura 1.1: A primeira versão de nosso integrador

Um termo muito comum quando falamos sobre o Spring Framework é dependência. Nosso Integrador possui duas, que são as classes DAO XML e Banco de Dados, ouseja, paraquenossointegradorexista, estasduasclassesobrigatoriamente precisam estar presentes.

Em um primeiro momento nosso sistema parece perfeito. O que poderia dar errado? Nada, a não ser três das quatro dificuldades expostas por Fred Brooks:

• Conformidade: tanto a classe de acesso a banco de dados quanto nosso DAO que acessa documentos XML precisam estar de acordo com as limitações impostas respectivamente pelo sistema gerenciador de banco de dados e pelas

Casa do Código Capítulo 1. Lide com o alto acoplamento de forma elegante restrições de esquema XML e do sistema de arquivos. Isto já era esperado, o problema é que a classe Integrador possui acesso direto aos detalhes de implementação de suas dependências.

• Mutabilidade: e se no futuro houver a necessidade de buscarmos dados não de arquivos XML, mas de outro banco de dados ou se o destino não for mais um banco de dados, mas um web service? Ainda pior: e se o cliente quiser decidir qual fonte e destino usar em tempo de execução?

• Complexidade: o Integrador além de lidar com as especificidades do seu maravilhoso algoritmo de processamento de dados também precisa lidar com as idiossincrasias das fontes de origem e destino dos dados.

AclasseIntegradorpossuialtoníveldeacoplamentoemrelaçãoaosdetalhesde implementação tanto da origem quanto do destino dos dados. Qualquer mudança em uma das dependências de Integrador e seu funcionamento pode ser comprometido. A qualidade de um software é inversamente proporcional ao grau de acoplamento de seus componentes.

Ainda há tempo de salvar este sistema. O que precisamos fazer é incluir abstrações. O que vêm a ser uma abstração? É o resultado do processo no qual, a partir da análise dos diversos usos de uma categoria de objetos, começamos a observar comportamentos que sempre estão presentes. Podemos pensar em interfaces Java e classes abstratas como abstrações, pois estas entidades contém comportamentos (leia-se métodos) que serão comuns a todas as classes que as implementem/realizem.

Vamos clarear o conceito de abstração, observando a segunda versão do nosso sistema de integração facilite:

1.1. Problema essencial: acoplamento Casa do Código

Figura 1.2: A segunda versão de nosso integrador

As interfaces Origem e Destino são abstrações. A classe Integrador não precisa conhecer detalhes sobre parseamento de arquivos XML ou a respeito de transações em bancos de dados. Só precisa saber que existe uma função que lhe retorna uma lista de registros a partir de uma origem e de um método que possa ser usado para persistir o resultado do seu processamento. Repare que fizemos uma abstração aqui ao identificarmos apenas o comportamento estritamente necessário para que uma origem seja uma origem e um destino um destino. Como resultado, reduzimos significativamente o acoplamento em nosso sistema, visto que agora o Integrador só tem acesso ao que de fato lhe interessa.

Você pode se perguntar neste momento: "como a complexidade do meu sistema foi reduzida se na prática acabaram de ser introduzidos dois elementos a mais no design original?”. Bem, primeiro o encapsulamento está maior, pois a classe Integrador não possui mais conhecimento a respeito de detalhes de implementação tanto da origem quanto do destino dos dados. Segundo, como o Integrador não sabe com qual fonte/destino de dados está lidando, qualquer classe que implemente as interfaces Origem ou Destino pode ser usada e por último, a mudança de comportamento em tempo de execução, onde na primeira versão do sistema, caso fosse necessário incluir uma nova fonte de dados, era necessário recompilar nosso código. Agora não mais, basta que nosso Integrador decida qual implementação

Casa do Código Capítulo 1. Lide com o alto acoplamento de forma elegante deseja usar.

Na realidade, nosso sistema adquiriu uma flexibilidade até então inexistente.

Qualquer um pode implementar tanto uma fonte quanto uma origem de dados para o sistema. Na imagem abaixo podemos ter uma noção desta flexibilidade.

Figura 1.3: Possibilidades infinitas para nosso sistema

O que fizemos foi na realidade aplicar o “Princípio da Inversão de Dependências” [10], onde Módulos de alto nível não devem depender de módulos de baixo nível, apenas devem depender de abstrações e Abstrações não devem depender de detalhes e sim detalhes devem depender de abstrações.

(Parte 1 de 5)

Comentários