Spring Framework (2.0)
Framework para
Desenvolvimento de Aplicações
em Java
Diego Pacheco
Dez/2007
Apostila desenvolvida especialmente para a Crom Microsystems.
Sua cópia ou reprodução é livre.
Sobre o Autor
Diego Pacheco
Técnico em Processamento de Dados e graduando em Ciências da Computação(7º sem.)
na Ulbra. Já trabalhou com desenvolvimento de software em VB, ASP, .NET e PHP.
Atualmente é Arquiteto de Software, certificado pela Sun, atuo desenvolvendo soluções
corporativas em arquitetura JEE, provendo coaching/mentoring em software e processo
de desenvolvimento de software. Gosto muito de música, tocar guitarra, jogar PSP,
Bloggar, Ler e principalmente as incríveis histórias do Conan. Mantenho o blog <
http://diego-pacheco.blogspot.com/> a mais de 3 anos.
Spring Framework – Framework para Desenvolvimento de Aplicações Java
Sumário
1. Introdução .................................................................................................................... 1-1
Objetivos ...................................................................................................................................1-2
Conceitos Básicos .................................................................................................................1-3
Cenários de uso ....................................................................................................................1-7
Portifólio ...............................................................................................................................1-10
Download ..............................................................................................................................1-12
Estrutura de Diretórios ..................................................................................................1-13
Exercícios ..............................................................................................................................1-15
Espaço para anotações ....................................................................................................1-16
2. Container IoC .............................................................................................................. 2-1
Objetivos ...................................................................................................................................2-2
IoC – Inversion of control ...............................................................................................2-3
Registrando Beans .............................................................................................................2-13
Singletons e lazy Initialization .................................................................................2-15
Lazy Initialization ...........................................................................................................2-18
Scopos dos Beans ................................................................................................................2-20
Criando seu próprio scope ............................................................................................2-23
Injeção via setter.................................................................................................................2-27
Injeção via construtor ......................................................................................................2-29
Injeção de coleções .............................................................................................................2-31
Injeção entre beans colaboradores ............................................................................2-36
Instanciando o contexto Web .......................................................................................2-40
Exercícios ..............................................................................................................................2-42
Espaço para anotações ....................................................................................................2-43
3. Manipulação de Beans .......................................................................................... 3-1
Objetivos ...................................................................................................................................3-2
Resource Loaders .................................................................................................................3-3
Init-Metohd e InitializingBean ...................................................................................3-4
Herança de Definições ......................................................................................................3-7
Validação ..............................................................................................................................3-10
Bean Wrapper......................................................................................................................3-13
BeanPostProcessors ............................................................................................................3-17
Diego Pacheco – http://diego-pacheco.blogspot.com
I
Spring Framework – Framework para desenvolvimento de aplicações Java
BeanFactoryPostProcessors ............................................................................................3-21
Property Editors .................................................................................................................3-25
Eventos ....................................................................................................................................3-30
PropertyPlaceholderConfigurer .................................................................................3-33
SingletonBeanFactoryLocator ......................................................................................3-36
Internacionalização .........................................................................................................3-40
Exercicios ..............................................................................................................................3-44
Espaço para anotações ....................................................................................................3-45
Diego Pacheco – http://diego-pacheco.blogspot.com
II
Spring Framework – Framework para desenvolvimento de aplicações Java
4. Persistência .................................................................................................................. 4-1
Objetivos ...................................................................................................................................4-2
Hierarquia de Exceptions ...............................................................................................4-3
Acesso a dados usando JDBC ........................................................................................4-5
Trabalhando com DataSources ....................................................................................4-5
Trabalhando com JDBCTemplate ..............................................................................4-7
Session Factory Bean ........................................................................................................4-11
Hibernate Template..........................................................................................................4-13
Transações Declarativas .................................................................................................4-18
Exercícios ..............................................................................................................................4-22
Espaço para anotações ....................................................................................................4-23
5. Facilitadores ................................................................................................................ 5-1
Objetivos ...................................................................................................................................5-2
Envio de E-mails ................................................................................................................5-3
Agendamento de tarefas com JDK Task .................................................................5-10
@Aspect Support .................................................................................................................5-16
Testing Support ...................................................................................................................5-23
AbstractDependencyInjectionSpringContextTests ..............................................5-24
AbstractAnnotationAwareTransactionalTests .....................................................5-27
AbstractTransactionalDataSourceSpringContextTests.....................................5-28
Remoting com RMI ...........................................................................................................5-29
Exercícios ..............................................................................................................................5-34
Espaço para anotações ....................................................................................................5-35
Diego Pacheco – http://diego-pacheco.blogspot.com
III
Spring Framework – Framework para Desenvolvimento de Aplicações Java
1. Introdução
Diego Pacheco – http://diego-pacheco.blogspot.com
Spring Framework – Framework para desenvolvimento de aplicações java
Objetivos
•
Conhecer os conceitos básicos;
•
Conhecer os principais cenários de uso;
•
Prover uma visão de todo o portifólio do Spring;
•
Saber onde baixar o Spring;
•
Conhecer a estrutura de diretórios dos fontes.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-2
Spring Framework – Framework para desenvolvimento de aplicações java
Conceitos Básicos
Spring framework, garanto a você que não é nenhum produto de limpeza,
até pode parecer pelo nome, mas não é. Spring é um dos frameworks líderes do
mercado full-stack Java/JEE. Esse framework é mantido pela empresa Interface21
que tem como presidente, Rod Johnson, o criador do Spring que é simplesmente
uma das maiores autoridades em Java. Spring prove diversos benefícios para muitos
projetos, aumentando a produtividade de desenvolvimento e a performance em
tempo de runtime em quanto ao mesmo tempo prove uma cobertura para testes e
muita qualidade para a aplicação.
O Spring prove soluções light-weight para construções de aplicações
corporativas. Enquanto ainda suporta e prove a possibilidade de se usar: transações
declarativas, acesso remoto através de RMI ou Web Services e muitas opções para
persistência de dados.
O Spring prove também uma solução completa MVC Framework e maneiras
transparentes e elegantes para integração de AOP ao seu software. Esse framework
é extremamente modular, assim você pode usar somente as partes que lhe
interessam. É possível usar IoC com Struts ou por exemplo, você pode optar por
usar somente a camada de integração com Hibernate ou a camada de abstração
para JDBC. Desenhado para não ser intrusivo, utilizando apenas ele mesmo ou o
mínimo de dependências para suas funcionalidades.
Esse framework foi muito bem dividido, e isso pode ser observado com
clareza na figura a baixo.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-3
Spring Framework – Framework para desenvolvimento de aplicações java
Figura 1.1 Visão Geral
Utilizando o Spring você já terá um ganho excelente em qualidade de
software em termos de design patterns, utilizando ele praticamente anula o uso de
patterns como Factory e ServiceLocator. Todo Objeto componente de sua aplicação
é por default para o Spring um singleton, assim favorecendo as boas práticas e a
performance.
A Empresa Interface21 e com certeza o Spring tem como missão os seguintes
valores:
•
J2EE Deveria ser muito fácil de usar
•
É melhor programar para interfaces do que para classes, Spring reduz o custo
e a complexidade de usar interfaces para zero.
•
JavaBeans oferece uma maneira excelente para configurar uma aplicação.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-4
Spring Framework – Framework para desenvolvimento de aplicações java
•
O Design OO é mais importante do que qualquer tecnologia de
implementação como, por exemplo, J2EE.
•
Exception checadas são mal utilizadas no Java. Um framework não deveria
forçar você a capturar exceptions que você não está apto a se recuperar.
•
Testabilidade é essencial, o Spring ajuda você a testar seu código mais
facilmente.
•
O Spring precisa ser prazeroso para quem desenvolve usando ele.
•
O Código de sua aplicação deveria não depender da API do Spring.
•
O Spring não compete com as boas soluções existentes, mas prove
integração dessas tecnologias, como exemplo o Hibernate, o Spring não
pretende desenvolver outra, apenas integrá-la e prover facilidades.
Algumas das funcionalidades do core do Spring são:
O Mais completo lightweight container: Prove centralização, automação de
configuração e escrita para seus objetos de negocio. É um container não intrusivo,
capaz de suportar sistemas complexos de um conjunto de componentes (POJO) de
baixo acoplamento, consistência e transparência. O Container traz agilidade ao
desenvolvimento e também testabilidade e uma alta escalabilidade, permitindo que
os componentes de software possam ser desenvolvidos e testados isoladamente.
Pode ser utilizado em qualquer ambiente de desenvolvimento J2SE ou J2EE.
Uma camada comum de abstração para Transações: Permite gerenciamento
transacional plugável com uma marcação transacional fácil, assim evitando
pequenos problemas de baixo nível. Estratégias para JTA e para um único JDBC
DataSource são incluídos. Em contraste com a JTA e o EJB CMT, as transações do
spring não estão disponíveis só em ambientes J2EE, é possível utilizar em ambiente
J2SE também.
Uma Camada de Abstração para JDBC: Prove uma hierarquia de exceptions a
partir de SQLException de maneira totalmente significativa. Simplifica o tratamento
de erros, e diminuiu muito a quantidade de código a ser escrito. Nunca mais será
necessário escrever um bloco finaly para usar JDBC.
Integração com Toplink, Hibernate, JDO, and iBATIS SQL Maps: Em termos
de resource holders, suporte a implementações de DAOs e estratégias transacionais.
Existe um suporte de primeira classe para Hibernate com muitas facilidades
providas pelo mecanismo de IoC.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-5
Spring Framework – Framework para desenvolvimento de aplicações java
Funcionalidade AOP: Totalmente integrado com o gerenciamento
configuracional do Spring, você pode utilizar AOP com qualquer objeto gerenciado
pelo Spring, adicionando aspectos em gerenciamento transacional, por exemplo.
Com Spring é possível ter transações declarativas sem EJB e até mesmo sem JTA,
caso você esteja utilizando um único banco de dados em um servidor tomcat, por
exemplo.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-6
Spring Framework – Framework para desenvolvimento de aplicações java
Cenários de uso
Podemos utilizar Spring nos mais diversos cenários, desde um simples applet
até mesmo nas mais complexas aplicações corporativas. Um exemplo típico de uso
do Spring em uma aplicação completa Java EE onde teremos:
Figura 1.2 Cenário completo de uso em JEE.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-7
Spring Framework – Framework para desenvolvimento de aplicações java
Uma camada de validações de formulários, soluções em upload de arquivos,
bind de objetos de domínio e claro, uma integração com JSP, Velocity, XSLT, PDF e
Excel. Após isso o contexto web, gerenciado pelo Spring e utilizando o Spring MVC.
No cerne das aplicações o contexto principal do Spring com o container IoC e
algumas funcionalidades, como envio de e-mails e acessos remotos através de RMI,
SOAP, Burlap, etc. Seguindo da camada de regras de negócio, onde temos
facilidades com o módulo de AOP e a integração com o módulo de ORM, chegando
finalmente na camada de persistência através do suporte rico ao Hibernate ou via
JDBC. Tudo isso rodando em um container JSP/Servlet como o Tomcat ou Jetty.
No caso de sua aplicação precisar fazer algum acesso remoto o Spring prove
isso de maneira transparente e elegante.
Figura 1.3 Cenário remoto.
É normal uma aplicação necessitar fazer acesso remoto a alguma outra
aplicação ou serviço, nesse cenário é interessante usar spring também, pois além de
facilitar a abstrair muito a complexidade de fazer esses acessos, você pode usar os
seus componentes que já estão sendo gerenciados pelo spring obtendo assim uma
máxima integração entre seus componentes de negócios e os componentes
remotos.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-8
Spring Framework – Framework para desenvolvimento de aplicações java
Podemos usar Spring também se for necessário fazer integração com EJB, é
possível utilizar os recursos da camada de acesso e abstração de EJB.
Figura 1.4 Cenário EJB.
O Spring permite você reutilizar seus pojos existentes e empacotados em
Stateless Session Beans, para serem usados em aplicações web escaláveis, que
precisam de segurança declarativa.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-9
Spring Framework – Framework para desenvolvimento de aplicações java
Portifólio
O Spring possui um portifólio muito abrangente, que é composto por uma
série de projetos “Spring...”, podemos dizer que é um ecossistema muito
diversificado, composto pelos seguintes projetos:
Spring Framework: Principal projeto do portifólio da Interface21, esse é o
framework base de todos os outros. Contém recursos como container IoC, suporte a
Hibernate, jdbc, aop, integração com os principais frameworks do mercado.
Spring Web Flow: framework web baseado em fluxos, prove a facilidade de
desenvolver modelos de ações dos usuários em alto nível de abstração. É possível
agrupar dois fluxos de controle e formar um modulo da junção dos dois.
Spring Web Services: Facilita o desenvolvimento de services SOAP,
permitindo a criação de web services flexíveis, com suporte a segurança WS,
permitindo ecriptação, decriptação. Possui integração com segurança ACGI. Além
disso, o Spring Web Services faz as boas práticas serem fáceis, ajudando você
desenvolver com baixo acoplamento entre o contrato e a implementação.
Spring Acegi: Acegi é uma solução flexível e poderosa para segurança de
aplicações Java. Dentre as principais facilidades estão: autenticação, autorização,
acesso baseado em instância, canal de segurança e capacidades de detecção
humana. Utiliza o contexto do Spring para suas configurações, configuração de
forma não intrusiva, utilizando filters.
Spring LDAP: Ajuda nas operações LDAP, baseada no pattern Spring’s
JdbcTemplate. O Framework alivia o desenvolvedor de abrir e fechar contextos,
fazer loopings através de NamingEnumerations, encoding/deconding de valores e
filtros.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-10
Spring Framework – Framework para desenvolvimento de aplicações java
Spring Rich Client: Framework para desenvolvimento de aplicações Rich
Client, é uma boa solução para construções de aplicações swing de maneira rápida
e de qualidade. Possuí um conjunto rico de UI Factories, o foco desse projeto e
prover boas práticas de maneira viável para o desenvolvimento swing, possui
integração com Jgoodies e layout managers ricos como o TableLayout.
Spring IDE para eclipse: Plugin para o ide eclipse com facilidades para o uso
de Spring. Preove auto complete para os xmls de configuração do Spring, módulo
visual para o Spring Web Flow, negação entre os beans do Spring, e visualização de
recursos AOP.
Spring BeanDoc: É uma ferramenta que facilita a documentação e desenho
gráfico dos beans do contexto do Spring. Desenhado para ser flexível e simples de
usar. BeanDoc pode facilitar a visualização das camadas da aplicação e como os
objetos interagem. Pode ser configurado por uma task ant.
Spring OSGI: Facilita a criação de aplicações Spring que irão rodar em um
framework OSGI, uma aplicação escrita dessa forma tem uma separação melhor
entre os módulos, com isso ganha a habilitada de remover, adicionar, atualizar os
módulos em tempo de execução.
Spring JavaConfig: Projeto que prove algumas anotações para efetuar o
mapeamento de pojos com menos configurações em XML. Esse projeto não
substitui completamente o uso de XML, mas consegue reduzir bastante em algumas
funcionalidades de injeção.
Spring.NET: Implementação do Core do Spring, com o seu container de IoC,
só que para a plataforma da Microsoft .NET, esse projeto não tem todas as
funcionalidades do Spring para Java, mas conta com muitos recursos do Spring
feitos em Java como AOP, gerenciamento transacional e integração com Web.
Spring Extensions: Projeto que é uma coleção de ferramentas para estender
as funcionalidades do Spring framework, prove facilidade de integrar o Spring com
outros frameworks. Dentre os tantos frameworks que são integrados com esse
projeto estão: ant, Lucene, cache declarativo com EHCache, Drools, Jakarta
Commons, engines de tamplates como Velocity, jBPM, etc.
Spring Batch: Prove suporte para execução de tarefas muito longas. Suporte
a programas batch os quais processam um volume muito grande de informações de
um banco de dados. Com suporte a agendamento automático ou manual após
falhas, esse projeto promove suporte de execuções batch para ambientes
corporativos.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-11
Spring Framework – Framework para desenvolvimento de aplicações java
Download
O
Spring
Framework
pode
ser
obtido
através
do
site:
http://www.springframework.org/download existe a possibilidade de baixar
somente o framework ou baixar o framework e suas dependências. A Versão do
Spring que será usada nessa apostila é a 2.0.6 , mas muitos itens descritos aqui são
válido também para a versão 1.2.x do framework.
O Spring framework necessita apenas uma versão do 1.5 JDK ou superior,
não é necessário criar variáveis de ambiente para o Spring. O Spring usa um
conjunto de frameworks muito grande, então é recomendado fazer download da
versão full com dependência que tem por volta de 60Mb.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-12
Spring Framework – Framework para desenvolvimento de aplicações java
Estrutura de Diretórios
Agora será detalhada a estrutura de diretórios da distribuição do Spring
framework. Ao descompactar os binários do Spring teremos uma estrutura de
diretórios da seguinte forma:
Figura 1.4 Estrutura de Diretórios da distribuição do Spring.
aspectj: Fontes dos testes dos artefatos que utilizam aspectj, aqui temos
alguns artefatos de transação feitos em aspectJ.
dist: Distribuição binárias dos fontes do Spring, aqui você encontrará os jars
do Spring, bem como todos os jars de todos os módulos separados.
docs: Contem toda a documentação do Spring, nessa você irá encontrar o
JavaDoc, Reference Guide, documentação das taglibs do Spring.
lib: Nesse diretório estão todas as dependências diretas e indiretas do Spring
framework, aqui você encontrar jars de diversos frameworks, como por exemplo
hibernate, struts, junit, ant.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-13
Spring Framework – Framework para desenvolvimento de aplicações java
mock: Fontes do mecanismo de mock que são utilizados para testes
unitários, nesse diretório você encontra os fontes dos testes dos mocks também.
samples: Nesse diretório existem diversos exemplos de mini-aplicações
utilizando o Spring Framework, como por exemplo a Petclinic que é uma clinica de
animais.
src: Contém todos os fontes do Spring framework, caso você precise desses
fontes para debugar o comportamento de algum código do Spring.
test: Nesse diretório você encontrará todos os fontes dos testes realizados
com o Spring, é útil para aprender como utilizar algumas classes do Spring.
tiger: Todos os fontes que utilizam recursos somente do Java 5.0 estão nesse
diretório, como por exemplo, annotations.
Dois arquivos que estão soltos no diretório principal e são interessantes são
o changelog.txt e o readme.txt. No arquivo changelog contém todas as mudanças
dessa versão do Spring como, por exemplo: quais são as novas features e quais
foram os bugs corrigidos. No arquivo readme nós temos a definição de cada
modulo do Spring com suas dependências, isso é muito útil se você deseja utilizar
somente alguns módulos do Spring e precisa saber as dependências.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-14
Spring Framework – Framework para desenvolvimento de aplicações java
Exercícios
1) Defina com suas palavras qual a utilidade do Spring Framework.
2) Cite três vantagens de se usar Spring framework.
3) Diga um cenário em que poderíamos utilizar Spring.
4) Diga uma das utilidades do arquivo readme.txt.
Diego Pacheco – http://diego-pacheco.blogspot.com
1-15
Spring Framework – Framework para desenvolvimento de aplicações java
Espaço para anotações
Diego Pacheco – http://diego-pacheco.blogspot.com
1-16
Spring Framework – Framework para Desenvolvimento de Aplicações Java
2. Container IoC
Diego Pacheco – http://diego-pacheco.blogspot.com
Spring Framework – Framework para desenvolvimento de aplicações java
Objetivos
•
Conhecer o conceito de IoC;
•
Saber utilizar Lazy initialization e Singletons;
•
Conhecer os escopos dos Beans;
•
Saber registrar beans no container do Spring;
•
Saber fazer injeções com setters e construtores;
•
Saber fazer injeções com coleções;
•
Saber fazer injeção entre beans colaboradores;
•
Saber instanciar o contexto do Spring.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-2
Spring Framework – Framework para desenvolvimento de aplicações java
IoC – Inversion of control
Com a grande demanda de desenvolvimento para o Java corporativo (JEE),
surgiu um problema comum, como ligar a camada de acesso a dados com a camada
de regra de negócio e por ventura a camada de apresentação? Uma solução é um
container de Ioc que também é chamada de Dependency Injection(DI), o Spring
framework possui um container de Ioc leve e implementa o pattern de setter
injection.
Esse container trabalha com serviços definidos pelo programador. Serviço é
um componente de software que foi projetado para ser reutilizado em muitos lugares
sem a necessidade de alteração de código, é possível alterar o seu comportamento
estendendo-o de alguma forma. A Idéia principal da injeção de dependências é
separar os Objetos e principalmente o objeto que usa um outro objeto não instanciar
diretamente esse objeto. Sendo assim, a principal vantagem da Dependency Injection
é separar uma interface de sua implementação concreta.
São dois tipos de injeção que o Spring utiliza em seu container de Ioc, veja:
Setter Injection: Nesse tipo de injeção de dependências se utiliza de métodos
setters baseados em propriedades e padrões de getters/setters da Sun. Você não
precisa ter a propriedade de fato em seu serviço, mas o padrão de nomenclatura
deve estar correto.
Constructor Injection: Nesse tipo de injeção de dependências é utilizado o
construtor da própria classe para fazer as injeções necessárias. Esse construtor pode
ter quantos parâmetros forem necessários.
Principais vantagens do uso de IoC do Spring:
•
Desacoplamento
•
Visão fácil de dependência
•
Facilidade para testes
•
Possibilita escrever aplicações para terceiros (fora do seu controle)
Para fixar melhor esse conceito considere o seguinte exemplo pratico: Imagine
que um Autor escreveu muitos livros, então considere os seguintes pojos:
Diego Pacheco – http://diego-pacheco.blogspot.com
2-3
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.bad;
import java.util.List;
public class Autor {
private String nome;
private List<Livro> livros;
public Autor() {}
public Autor(String nome) {
super();
this.nome = nome;
}
public void listarPorNome(){
Listar l = new Listar();
List ret = l.list(nome);
System.out.println( (ret.size()==0) ? "NRE" : ret );
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public List<Livro> getLivros() {
return livros;
}
public void setLivros(List<Livro> livros) {
this.livros = livros;
}
}
Código 2.1 Autor.java
Diego Pacheco – http://diego-pacheco.blogspot.com
2-4
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.bad;
public class Livro {
private
private
private
private
Autor autor;
String titulo;
String editora;
int ano;
public Livro() {}
public Livro(Autor autor, String titulo, String editora, int ano) {
super();
this.autor = autor;
this.titulo = titulo;
this.editora = editora;
this.ano = ano;
}
public Autor getAutor() {
return autor;
}
public void setAutor(Autor autor) {
this.autor = autor;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public String getEditora() {
return editora;
}
public void setEditora(String editora) {
this.editora = editora;
}
public int getAno() {
return ano;
}
public void setAno(int ano) {
this.ano = ano;
}
@Override
public String toString() {
return "titulo: " + titulo + " editor: " + editora +
" ano: " + ano;
}
}
Código 2.2 Livro.java
Diego Pacheco – http://diego-pacheco.blogspot.com
2-5
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.bad;
import java.util.ArrayList;
import java.util.List;
public class Listar {
public List list(String nome){
Autor a = new Autor("Diego Pacheco");
List<Livro> livros = new ArrayList<Livro>();
livros.add(new Livro(a,"Livro da Vida","Do Livro",2000));
livros.add(new Livro(a,"Spring for Dummies","O'really",2001));
livros.add(new Livro(a,"Bit ou não","Variados Editora",2002));
List<Livro> achados = new ArrayList<Livro>();
for(Livro l: livros){
if (l.getAutor().getNome().equals(nome))
achados.add(l);
}
return achados;
}
}
Código 2.3 Listar.java
package com.targettrust.spring.bad;
public class MainTest {
public static void main(String[] args) {
Autor autor = new Autor("Rod");
autor.listarPorNome();
autor.setNome("Diego Pacheco");
autor.listarPorNome();
}
}
Código 2.4 MainTest.java
Diego Pacheco – http://diego-pacheco.blogspot.com
2-6
Spring Framework – Framework para desenvolvimento de aplicações java
Nós temos os seguintes objetos: Autor, Livro, Listar e MainTest. Nesse exemplo
um Autor pode ter vários livros por isso dentro do Pojo de Autor temos List<Livro>
e a classe Listar se encarrega de armazenar os livros e autores e prover uma procura
sobre esses dados. Como vocês devem ter percebido o pojo Autor contém um
método chamado: listarPorNome que instância esse objeto Listar e procura pelos
livros do autor. Esse exemplo por mais simplório, serve para demonstrar que existe
um forte acoplamento entre o pojo Autor e a classe que lista os Livros por Autor,
outro grande problema nesse exemplo é que não existem interfaces. O que
aconteceria se um Autor pudesse ter outras coisas além de livros como, por exemplo:
artigos, co-autorias, vídeos? Nesse caso essa mudança iria implicar em um refactoring
muito grande nessas classes, mas como poderíamos resolver esse problema?
Diego Pacheco – http://diego-pacheco.blogspot.com
2-7
Spring Framework – Framework para desenvolvimento de aplicações java
Solução: Criar um interface Publicável e o Livro irá implementar essa classe, no
pojo de Autor mude de uma lista de Livros para uma List de Publicáveis, assim
criamos a possibilidade de um Autor ter diversos itens em seu portifólio como, por
exemplo: Livros, Artigos, Co-autuações. Para resolver o problema de forma de
armazenamento e procura de livros, foi criada a interface Listavel e a classe Listar
implementa essa interface, agora podemos criar outra classe que faça acesso à base
de dados, claro que esse classe deve implementar Listavel. No pojo do Autor
precisamos colocar um atributo Listavel e através desse atributo que vamos acessar
os dados. Essas novas classes iram ficar conforme os fontes a baixo.
package com.targettrust.spring.bad.ok;
import java.util.List;
public class Autor {
private String nome;
private List<Publicavel> publicaveis;
private Listavel list;
public Autor() {}
public Autor(String nome) {
super();
this.nome = nome;
}
public void listarPorNome(){
List ret = list.list(nome);
System.out.println( (ret.size()==0) ? "NRE" : ret );
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public List<Publicavel> getPublicaveis() {
return publicaveis;
}
public void setPublicaveis(List<Publicavel> publicaveis) {
this.publicaveis = publicaveis;
}
public Listavel getList() {
return list;
}
public void setList(Listavel list) {
this.list = list;
}
}
Código 2.5 Autor.java
Diego Pacheco – http://diego-pacheco.blogspot.com
2-8
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.bad.ok;
public class Livro implements Publicavel{
private
private
private
private
Autor autor;
String titulo;
String editora;
int ano;
public Livro() {}
public Livro(Autor autor, String titulo, String editora, int ano) {
super();
this.autor = autor;
this.titulo = titulo;
this.editora = editora;
this.ano = ano;
}
@Override
public String getNome() {
return getTitulo();
}
@Override
public String getTipo() {
return "Livro";
}
public String getAutor() {
return autor.getNome();
}
public void setAutor(Autor autor) {
this.autor = autor;
}
public String getTitulo() {
return titulo;
}
public void setTitulo(String titulo) {
this.titulo = titulo;
}
public String getEditora() {
return editora;
}
public void setEditora(String editora) {
this.editora = editora;
}
public int getAno() {
return ano;
}
public void setAno(int ano) {
this.ano = ano;
}
@Override
Diego Pacheco – http://diego-pacheco.blogspot.com
2-9
Spring Framework – Framework para desenvolvimento de aplicações java
public String toString() {
return "titulo: " + titulo + " editor: " + editora +
" ano: " + ano;
}
}
Código 2.6 Livro.java
package com.targettrust.spring.bad.ok;
public interface Publicavel {
public String getAutor();
public String getNome();
public String getTipo();
}
Código 2.7 Publicavel.java
package com.targettrust.spring.bad.ok;
import java.util.List;
public interface Listavel {
public List<Publicavel> list(String nome);
}
Código 2.8 Listavel.java
Diego Pacheco – http://diego-pacheco.blogspot.com
2-10
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.bad.ok;
import java.util.ArrayList;
import java.util.List;
public class Listar implements Listavel{
public List<Publicavel> list(String nome) {
Autor a = new Autor("Diego Pacheco");
List<Publicavel> publicaveis = new ArrayList<Publicavel>();
publicaveis.add(new Livro(a,"Livro da Vida","Do Livro",2000));
publicaveis.add(new Livro(a,"Spring for
Dummies","O'really",2001));
publicaveis.add(new Livro(a,"Bit ou não","Variados
Editora",2002));
List<Publicavel> achados = new ArrayList<Publicavel>();
for(Publicavel p: publicaveis){
if (p.getAutor().equals(nome))
achados.add(p);
}
return achados;
}
}
Código 2.9 Listar.java
package com.targettrust.spring.bad.ok;
public class MainTest {
public static void main(String[] args) {
Autor autor = new Autor();
autor.setList(new Listar());
autor.setNome("Rod");
autor.listarPorNome();
autor.setNome("Diego Pacheco");
autor.listarPorNome();
}
}
Código 2.10 MainTest.java
Diego Pacheco – http://diego-pacheco.blogspot.com
2-11
Spring Framework – Framework para desenvolvimento de aplicações java
Nesse exemplo conseguimos resolver os problemas citados acima, mas
utilizamos a IoC “na mão”, ou seja, nós mesmos injetamos as dependências, a solução
é boa, mas isso em um sistema grande seria muito custoso de se fazer, nesse ponto
entra o container de IoC do Spring. O Container possibilita de maneira fácil e simples
a injeção dessas dependências e reduz o custo de se trabalhar com essas interfaces
quase à zero.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-12
Spring Framework – Framework para desenvolvimento de aplicações java
Registrando Beans
Agora vamos ver como registrar essas classes no contexto do Spring. Esse
registro é muito simples, ele consiste em apontar para uma classe Java no seu
classpath e dar um id a esse bean. Existem outras configurações que podemos fazer
sobre esses beans, mas vamos começar mostrando como declarar um bean no
Spring.
<?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-2.0.xsd"
>
<bean
id="autor"
class="com.targettrust.spring.bad.ok.Autor"
/>
</beans>
Código XML 2.1 Spring-beans.xml
Para recuperarmos esse bean do Contexto do Spring, precisamos instanciar um
contexto do Spring e solicitar o bean apartir do ID para o contexto, conforme
exemplo a baixo.
package com.targettrust.spring.primeiro;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/primeiro/Springbeans.xml");
Object bean = bf.getBean("autor");
System.out.println("Autor: " + bean);
}
}
Código 2.11 Obtendo um bean do Spring
Diego Pacheco – http://diego-pacheco.blogspot.com
2-13
Spring Framework – Framework para desenvolvimento de aplicações java
A BeanFactory é uma interface Java que representa o Container Ioc, essa
BeanFactory
precisa
ser instanciada,
nesse
exemplo
foi
usado
a
factory
ClassPathXmlApplicationContext que é uma factory que leva em consideração xmls
de configurações que estão no classpath. Existem várias factories no Spring, uma para
cada situação, por exemplo, existe uma factory que é utilizada para subir o contexto
do Spring em um ambiente Servlet.
Após a inicialização do contexto do Spring podemos utilizar o método getBean
para recuperar um bean do Spring, nesse exemplo estamos passando o ID do bean
que foi o mesmo que registramos no XML: Spring-beans.xml
Outra forma de criarmos a BeanFactory seria utilizar um ClassPathResource
que aponta para o Xml dos beans e depois utilizar a factory XmlBeanFactory.
Conforme o exemplo de código a baixo.
ClassPathResource resource = new
ClassPathResource("/com/targettrust/spring/primeiro/Spring-beans.xml");
BeanFactory bf = new XmlBeanFactory(resource);
Código 2.12 outra bean factory
É possível registrar um Bean no contexto do Spring programaticamente, para
isso é necessário utilizar um objeto BeanDefinition que é o objeto que configura o
bean no Spring.
BeanDefinition beanDefinition = new RootBeanDefinition(Livro.class,
RootBeanDefinition.AUTOWIRE_NO);
((BeanDefinitionRegistry)bf).registerBeanDefinition("livro",
beanDefinition);
Object beanOutro = bf.getBean("livro");
System.out.println("Livro: " + beanOutro);
Código 2.13 Registra um bean programaticamente
Diego Pacheco – http://diego-pacheco.blogspot.com
2-14
Spring Framework – Framework para desenvolvimento de aplicações java
Singletons e lazy Initialization
Para aumentar a performance de sua aplicação com qualidade e aplicando
design patterns o Spring por default transforma qualquer bean registrado nele em
um singleton. Singleton é um padrão de projeto (Design Pattern) que consiste em
manter apenas uma instância de um determinado objeto por classloader. É um
pattern muito aplicado para conexões com banco de dados, por exemplo. Podemos
ver isso através do seguinte teste.
package com.targettrust.spring.singleton;
import java.util.ArrayList;
import java.util.List;
public class Uf {
private String nome;
private String sigla;
private List<Uf> ufs;
public Uf() {
System.out.println("Inicio do processamento dos estados...");
initUfs();
}
private Uf(String nome, String sigla) {
this.nome = nome;
this.sigla = sigla;
}
private void initUfs() {
ufs = new ArrayList<Uf>();
ufs.add(new Uf("Acre","AC"));
ufs.add(new Uf("Alagoas","AL"));
ufs.add(new Uf("Amapá","AP"));
ufs.add(new Uf("Amazonas","AM"));
ufs.add(new Uf("Bahia","BA"));
ufs.add(new Uf("Ceará","CE"));
ufs.add(new Uf("Distrito Federal","DF"));
ufs.add(new Uf("Goiás","GO"));
ufs.add(new Uf("Espírito Santo","ES"));
ufs.add(new Uf("Maranhão","MA"));
ufs.add(new Uf("Mato Grosso","MT"));
ufs.add(new Uf("Mato Grosso do Sul","MS"));
ufs.add(new Uf("Minas Gerais","MG"));
ufs.add(new Uf("Pará","PA"));
ufs.add(new Uf("Paraiba","PB"));
ufs.add(new Uf("Paraná","PR"));
ufs.add(new Uf("Pernambuco","PE"));
ufs.add(new Uf("Piauí","PI"));
ufs.add(new Uf("Rio de Janeiro","RJ"));
ufs.add(new Uf("Rio Grande do Norte","RN"));
ufs.add(new Uf("Rio Grande do Norte","RS"));
ufs.add(new Uf("Rondônia","RO"));
Diego Pacheco – http://diego-pacheco.blogspot.com
2-15
Spring Framework – Framework para desenvolvimento de aplicações java
ufs.add(new
ufs.add(new
ufs.add(new
ufs.add(new
ufs.add(new
Uf("Rorâima","RR"));
Uf("São Paulo","SP"));
Uf("Santa Catarina","SC"));
Uf("Sergipe","SE"));
Uf("Tocantins","TO"));
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getSigla() {
return sigla;
}
public void setSigla(String sigla) {
this.sigla = sigla;
}
public List<Uf> getUfsBrazil(){
return ufs;
}
public void showInstance(){
System.out.println(super.toString());
}
public String toString() {
return sigla;
}
}
Código 2.14 Bean Uf
<?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-2.0.xsd"
>
<bean
id="uf"
class="com.targettrust.spring.singleton.Uf"
/>
</beans>
Código XML 2.2 Spring-beans.xml
Diego Pacheco – http://diego-pacheco.blogspot.com
2-16
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.singleton;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUfs {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/singleton/Springbeans.xml");
Uf bean1 = (Uf)bf.getBean("uf");
System.out.println("ufs: " + bean1.getUfsBrazil());
bean1.showInstance();
Uf bean2 = (Uf)bf.getBean("uf");
System.out.println("ufs: " + bean2.getUfsBrazil());
bean2.showInstance();
Uf bean3 = (Uf)bf.getBean("uf");
System.out.println("ufs: " + bean3.getUfsBrazil());
bean3.showInstance();
}
}
Código 2.15 Teste
Se executarmos esse programa, o resultado será algo semelhante ao
representado na figura abaixo.
Inicio do processamento dos estados...
ufs: [AC, AL, AP, AM, BA, CE, DF, GO, ES, MA, MT, MS, MG, PA, PB, PR, PE,
PI, RJ, RN, RS, RO, RR, SP, SC, SE, TO]
com.targettrust.spring.singleton.Uf@3ecfff
ufs: [AC, AL, AP, AM, BA, CE, DF, GO, ES, MA, MT, MS, MG, PA, PB, PR, PE,
PI, RJ, RN, RS, RO, RR, SP, SC, SE, TO]
com.targettrust.spring.singleton.Uf@3ecfff
ufs: [AC, AL, AP, AM, BA, CE, DF, GO, ES, MA, MT, MS, MG, PA, PB, PR, PE,
PI, RJ, RN, RS, RO, RR, SP, SC, SE, TO]
com.targettrust.spring.singleton.Uf@3ecfff
Código 2.16 Resultado da Execução
Perceba que a criação dos estados ocorre somente na primeira vez, mas nas
outras vezes já está em memória, logo além, se não fizer duas vezes o mesmo
processamento, existe um ganho de performance.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-17
Spring Framework – Framework para desenvolvimento de aplicações java
Também é possível desativar esse comportamento, ou seja, é possível
configurar no spring para que o bean em questão não seja criado como um
Singleton. Para isso, basta alterar o registro do bean no Spring, conforme no XML
abaixo:
<?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-2.0.xsd"
>
<bean
id="uf"
class="com.targettrust.spring.singleton.Uf"
scope="prototype"
/>
</beans>
Código XML 2.3 Spring-beans.xml
Neste mesmo capítulo serão explicados e exemplificados melhor os possíveis
escopos de beans no Spring.
Lazy Initialization
Outro recurso importante é o Lazy Initialization, com ele podemos fazer com
que o Spring só carregue os beans que forem solicitados, ou seja, se temos 50 beans
declarados no contexto do Spring e apenas 10 são utilizados, os outros 40 beans não
vão ser instanciados, e assim evitamos um processamento desnecessário e ganhamos
em desempenho.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-18
Spring Framework – Framework para desenvolvimento de aplicações java
Para fazer tal configuração é necessário configurar no XML de beans do Spring
o atributo lazy-init="true". Veja o exemplo de como faz isso no XML abaixo:
<?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-2.0.xsd"
>
<bean
id="uf"
class="com.targettrust.spring.singleton.Uf"
scope="prototype"
lazy-init="true"
/>
</beans>
Código XML 2.4 Spring-beans.xml um exemplo lazy initialization.
É sempre válido configurar esse comportamento do framework. O Default do
Spring é começar com lazy-init=”false”,
então sempre que possível altere essa
configuração para true.
Podemos configurar no Spring que todos os beans de um determinado
arquivo XML de configurações por default assumam o mesmo valor, podemos fazer
isso através do atributo default-lazy-init esse atributo só pode ser setado no modo
beans que é a raiz de configurações.
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="uf"
class="com.targettrust.spring.singleton.Uf"
scope="prototype"
/>
</beans>
Código XML 2.4 Spring-beans.xml um exemplo de default lazy initialization.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-19
Spring Framework – Framework para desenvolvimento de aplicações java
Scopos dos Beans
Scopo se refere à visibilidade de um objeto gerenciado pelo Spring e também
está relacionado ao seu tempo de vida. Existem os seguintes scopos de beans no
Spring.
Scopo
Descrição
singleton
Uma única instância de objeto para todo o contexto do Spring.
prototype
Múltiplas instâncias de um objeto para o container do Spring.
request *
Escopo relacionado ao ciclo de vida HTTP Request, a cada
request teremos outra instância de bean no Spring
session *
Escopo relacionado ao ciclo de vida HTTP Session, uma única
instância do Bean por session.
global
Escopo relacionado ao ciclo de vida global HTTP Session, bean
session *
válido em uma session global. Utilizado para portlets.
* Escopos que só são válidos em um contexto web-aware, ou seja, em uma aplicação
JSP/Servlet ou JEE. Criados por uma factory específica para Web, como por exemplo:
XmlWebApplicationContext.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-20
Spring Framework – Framework para desenvolvimento de aplicações java
Podemos ver na prática a diferença entre singleton e prototype no exemplo
abaixo. Nesse exemplo o mesmo bean é registrado de maneiras diferentes, isso é
perfeitamente possível.
package com.targettrust.spring.scope;
public class SimpleBean {
private Long id = 0L;
public SimpleBean() {}
public SimpleBean(Long id) {
super();
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return super.toString() + " id: " + id;
}
}
Código 2.17 SimpleBean.java.
<?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-2.0.xsd"
>
<bean
id="beanA"
class="com.targettrust.spring.scope.SimpleBean"
scope="singleton"
/>
<bean
id="beanB"
class="com.targettrust.spring.scope.SimpleBean"
scope="prototype"
/>
</beans>
Código XML 2.5 Spring-beans.xml xml de configuração.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-21
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.scope;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestScope {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/scope/Springbeans.xml");
SimpleBean
SimpleBean
SimpleBean
SimpleBean
beanA
beanA1
beanB
beanB1
=
=
=
=
(SimpleBean)bf.getBean("beanA");
(SimpleBean)bf.getBean("beanA");
(SimpleBean)bf.getBean("beanB");
(SimpleBean)bf.getBean("beanB");
System.out.println("BeanA
System.out.println("BeanA1
System.out.println("BeanB
System.out.println("BeanB1
:
:
:
:
"
"
"
"
+
+
+
+
beanA);
beanA1);
beanB);
beanB1);
}
}
Código 2.18 Teste de Scopes.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-22
Spring Framework – Framework para desenvolvimento de aplicações java
Criando seu próprio scope
No Spring framework 2.0.X podemos criar nosso próprio scope e ainda mais,
podemos redefinir os scopos baseados em web-aware. Os únicos scopos que são
intocáveis são: prototype e singleton, se tentarmos reescrevê-los o Spring irá levantar
uma IllegalArgumentException.
Imagine que em sua aplicação surgiu a necessidade de ter controle sobre
todos os objetos Pessoa criados, como poderíamos fazer isso sem reescrever toda a
aplicação? Criando o nosso próprio scopo de bean seria uma forma.
package com.targettrust.spring.scope.myscope;
public class Pessoa {
private String nome;
public Pessoa() {
}
public Pessoa(String nome) {
super();
this.nome = nome;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((nome == null) ? 0 :
nome.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
return (obj == null) ? false : nome.equals(((Pessoa)
obj).getNome());
}
@Override
public String toString() {
return "nome: " + nome;
}
}
Código 2.19 Pessoa.java.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-23
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.scope.myscope;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SuppressWarnings("unused")
public class TestScopes {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/scope/myscope/Spri
ng-beans.xml");
Pessoa p1 = (Pessoa)bf.getBean("pessoa1");
Pessoa p2 = (Pessoa)bf.getBean("pessoa2");
Pessoa p3 = (Pessoa)bf.getBean("pessoa3");
Pessoa p4 = (Pessoa)bf.getBean("pessoa4");
System.out.println("Todas as pessoas: " +
ThreadLocalScope.tl.get());
p3.setNome("Spider-Pig");
System.out.println("Todas as pessoas: " +
ThreadLocalScope.tl.get());
}
}
Código 2.20 Classe de testesTestScopes.java.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-lazy-init="false"
>
<bean
class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="threadLocal">
<bean
class="com.targettrust.spring.scope.myscope.ThreadLocalScope"/>
</entry>
</map>
</property>
</bean>
<bean id="pessoa1"
class="com.targettrust.spring.scope.myscope.Pessoa"
scope="threadLocal"
>
<property name="nome" value="Diego Pacheco"/>
</bean>
<bean id="pessoa2"
class="com.targettrust.spring.scope.myscope.Pessoa"
Diego Pacheco – http://diego-pacheco.blogspot.com
2-24
Spring Framework – Framework para desenvolvimento de aplicações java
scope="threadLocal"
>
<property name="nome" value="Rod Johnson"/>
</bean>
<bean id="pessoa3"
class="com.targettrust.spring.scope.myscope.Pessoa"
scope="threadLocal"
>
<property name="nome" value="Juergen Hoeller"/>
</bean>
<bean id="pessoa4"
class="com.targettrust.spring.scope.myscope.Pessoa"
scope="singleton"
>
<property name="nome" value="Ninguem me viu!!!"/>
</bean>
</beans>
Código XML 2.6 Spring-beans.xml scope customizado.
package com.targettrust.spring.scope.myscope;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class ThreadLocalScope implements Scope{
public static ThreadLocal<Map<String, Object>> tl;
public ThreadLocalScope() {
tl = new ThreadLocal<Map<String,Object>>();
tl.set(new HashMap<String, Object>());
}
@Override
public Object get(String name, ObjectFactory objectFactory) {
synchronized(tl){
Object realTarget = objectFactory.getObject();
if (realTarget instanceof Pessoa){
tl.get().put(realTarget.hashCode() + ";",
realTarget);
return realTarget;
}
throw new RuntimeException("Esse scopo só pode ser
utilizado para objetos Pessoa ");
}
}
@Override
public Object remove(String name) {
synchronized(tl){
Object obj = tl.get().remove(name);
Diego Pacheco – http://diego-pacheco.blogspot.com
2-25
Spring Framework – Framework para desenvolvimento de aplicações java
return obj;
}
}
@Override
public void registerDestructionCallback(String name, Runnable
callback){
throw new UnsupportedOperationException("Essa operação de
registerDestructionCallback, não suportada!");
}
@Override
public String getConversationId() {
return null;
}
}
Código 2.21 ThreadLocalScope.java classe de scope customizada.
Para criar um scopo personalizado no Spring é necessário implementar a
interface
org.springframework.beans.factory.config.Scope,
a
implementação
dessa interface é simples, basicamente só precisamos nos preocupar com os métodos
get e remove. Após a implementação dessa interface só será necessário registrar no
spring o seu novo scopo, isso é feito com a seguinte configuração em xml:
<bean
class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="threadLocal">
<bean
class="com.targettrust.spring.scope.myscope.ThreadLocalScope"/>
</entry>
</map>
</property>
</bean>
Código XML 2.7 Definição de scope customizado.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-26
Spring Framework – Framework para desenvolvimento de aplicações java
Injeção via setter
Essa é uma das duas formas que o Spring faz injeção de dependências, ele
utiliza um método setter conforme padrão da Sun e através desse método setta os
valores no objeto em questão.
package com.targettrust.spring.setter;
public class Aluno {
private
private
private
private
String nome;
Integer idade;
boolean desconto;
Character sexo;
public Aluno() {}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Integer getIdade() {
return idade;
}
public void setIdade(Integer idade) {
this.idade = idade;
}
public boolean isDesconto() {
return desconto;
}
public void setDesconto(boolean desconto) {
this.desconto = desconto;
}
public Character getSexo() {
return sexo;
}
public void setSexo(Character sexo) {
this.sexo = sexo;
}
@Override
public String toString() {
return "nome: " + nome +
" idade: " + idade +
" desconto: " + desconto +
" sexo: " + sexo;
}
}
Código 2.22 Aluno.java.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-27
Spring Framework – Framework para desenvolvimento de aplicações java
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="aluno"
class="com.targettrust.spring.setter.Aluno"
>
<property name="nome"
value="Diego" />
<property name="idade"
value="22" />
<property name="desconto" value="true" />
<property name="sexo"
value="M" />
</bean>
</beans>
Código XML 2.8 Configuração de injeção via setter
package com.targettrust.spring.setter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSetter {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/setter/Springbeans.xml");
System.out.println(bf.getBean("aluno"));
}
}
Código 2.23 TestSetter.java
Não existe nada de mágico na injeção via setter, é simples, basta ter o método
setter e o tipo de dado injetado ser o mesmo.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-28
Spring Framework – Framework para desenvolvimento de aplicações java
Injeção via construtor
Esta é a outra forma de injeção de dependência do Spring. As dependências
são injetadas através de um construtor. Considere a seguinte classe Java:
package com.targettrust.spring.constructor;
public class Pessoa {
private String nome;
private Integer idade;
private boolean cartaMorotista;
public Pessoa(String nome, Integer idade, boolean cartaMorotista) {
super();
this.nome = nome;
this.idade = idade;
this.cartaMorotista = cartaMorotista;
}
@Override
public String toString() {
return " nome: " + nome +
" idade: " + idade +
" morotista: " + cartaMorotista;
}
}
Código 2.24 Pessoa.java
Para injetarmos nome, idade, cartaMotorista, é só efetuar essa injeção via
construtor no XML de configuração do Spring, conforme código XML abaixo:
<?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-2.0.xsd"
>
<bean
id="pessoa"
class="com.targettrust.spring.constructor.Pessoa"
>
<constructor-arg value="Diego Pacheco" />
<constructor-arg value="22" />
<constructor-arg value="false" />
</bean>
</beans>
Código XML 2.9 Configuração de injeção via construtor
Diego Pacheco – http://diego-pacheco.blogspot.com
2-29
Spring Framework – Framework para desenvolvimento de aplicações java
Para ver a injeção funcionando considere a classe de testes abaixo:
package com.targettrust.spring.constructor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestConstructor {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/constructor/Spring
-beans.xml");
System.out.println(bf.getBean("pessoa"));
}
}
Código 2.25 TestConstructor.java Teste de construtor
Ao rodar esses códigos você terá um retorno semelhante a este:
nome: Diego Pacheco idade: 22 motorista: false
Caso você tenha um construtor que receba uma String e um número, o Spring
pode acabar sentando valores indesejados, para resolver esse tipo de situação,
podemos especificar o tipo do argumento do construtor, conforme exemplo de XML
abaixo.
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
Código XML 2.10 Exemplo de tipo de argumento para construtor.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-30
Spring Framework – Framework para desenvolvimento de aplicações java
Uma outra opção seria informar qual é a posição do parâmetro no construtor,
isso nós chamamos de index, começa em zero(0), como segue o exemplo:
<bean
id="animal"
class="com.targettrust.spring.constructor.Animal"
>
<constructor-arg index="1"
<constructor-arg index="0"
value="Black" />
value="Dog" />
</bean>
Código XML 2.11 Exemplo de tipo de argumento para construtor com index.
Injeção de coleções
Por deafult o Spring possui tags específicas para injeção de coleções, é possível
injetar: Map, List, Properties e Set. De fato podemos injetar qualquer Collection, mas
para injetar uma coleção que não seja uma das citadas, será necessário usar um
Custon Property Editor. Para fazer as injeções das coleções “nativas” do Spring,
utilizamos as tags: <map/>, <list/>, <set/> e <props/>. Considerando o seguinte
exemplo:
<?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-2.0.xsd"
>
<bean
id="estadio"
class="com.targettrust.spring.collection.Estadio"
>
<property name="pessoas">
<set>
<value>Diego</value>
<value>Rod</value>
<value>Alef</value>
</set>
</property>
<property name="cadeiras">
<map>
<entry>
<key><value>1</value></key>
<value>diego</value>
</entry>
<entry>
<key><value>2</value></key>
<value>Rod</value>
Diego Pacheco – http://diego-pacheco.blogspot.com
2-31
Spring Framework – Framework para desenvolvimento de aplicações java
</entry>
</map>
</property>
<property name="vededoresPipoca">
<list>
<value>Ze</value>
<value>JoZe</value>
<value>MaisEh</value>
</list>
</property>
<property name="detalhes">
<value>
estadio.luz=forte
estadio.taman.hq.full=grande
estadio.fundac.since=10/10/2001
estadio.status.now=ativo
</value>
</property>
</bean>
</beans>
Código XML 2.12 Exemplo de injeção de collections.
Para esse código de injeções de coleções em XML precisamos de uma classe
Java, conforme a definida a baixo:
package com.targettrust.spring.collection;
import
import
import
import
java.util.List;
java.util.Map;
java.util.Properties;
java.util.Set;
public class Estadio {
private
private
private
private
Set<String> pessoas;
Map<Integer, String> cadeiras;
List<String> vededoresPipoca;
Properties detalhes;
public Estadio() {}
public Set<String> getPessoas() {
return pessoas;
}
public void setPessoas(Set<String> pessoas) {
this.pessoas = pessoas;
}
Diego Pacheco – http://diego-pacheco.blogspot.com
2-32
Spring Framework – Framework para desenvolvimento de aplicações java
public Map<Integer, String> getCadeiras() {
return cadeiras;
}
public void setCadeiras(Map<Integer, String> cadeiras) {
this.cadeiras = cadeiras;
}
public List<String> getVededoresPipoca() {
return vededoresPipoca;
}
public void setVededoresPipoca(List<String> vededoresPipoca) {
this.vededoresPipoca = vededoresPipoca;
}
public Properties getDetalhes() {
return detalhes;
}
public void setDetalhes(Properties detalhes) {
this.detalhes = detalhes;
}
@Override
public String toString() {
return " pessoas: " + pessoas + "\n" +
" cadeiras: " + cadeiras + "\n" +
" Vededores de Pipoca: " + vededoresPipoca + "\n" +
" detalhes: " + detalhes;
}
}
Código 2.26 Estadio.java Classe que usa Collections.
Podemos testar esses recursos através do teste abaixo:
package com.targettrust.spring.collection;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestCollections {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/collection/Springbeans.xml");
System.out.println(bf.getBean("estadio"));
}
}
Código 2.26 TestCollections.java Classe de testes.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-33
Spring Framework – Framework para desenvolvimento de aplicações java
Existem outras váriaveis para a injeção de properties, no exemplo acima foi
utilizada a forma mais simplificada, mas poderíamos fazer da forma “completa”,
conforme exemplo abaixo:
<property name="detalhes">
<props>
<prop key="estadio.luz">forte</prop>
<prop key="estadio.taman.hq.full">grande</prop>
<prop key="estadio.fundac.since">10/10/2001</prop>
<prop key="estadio.status.now">ativo</prop>
</props>
</property>
Código XML 2.13 Outra forma de injeção de Properties.
Dica: Se for explicitamente necessário injetar uma coleção nula, ou settar null em
alguma propriedade de algum bean do Spring, podemos utilizar a tag <null/>.
Podemos injetar qualquer tipo de coleção através do uso de property editors,
essa é uma solução muito elegante do Spring. Quando registramos um editor do tipo
Class, por exemplo, toda vez que o Spring for injetar um valor em um objeto que a
propriedade seja Class ele vai invocar esse property editor. Veja como usar a
Collection do Tipo LinkedList no exemplo abaixo:
package com.targettrust.spring.collection;
import java.util.LinkedList;
public class Cidade {
private LinkedList<String> ruas;
public Cidade() {}
public LinkedList<String> getRuas() {
return ruas;
}
public void setRuas(LinkedList<String> ruas) {
this.ruas = ruas;
}
}
Código 2.27 Cidade.java Classe que usa LinkedList.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-34
Spring Framework – Framework para desenvolvimento de aplicações java
<?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-2.0.xsd"
>
<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigurer"
>
<property name="customEditors">
<map>
<entry key="java.lang.Class">
<bean
class="org.springframework.beans.propertyeditors.ClassEditor" />
</entry>
<entry key="java.util.LinkedList">
<bean
class="org.springframework.beans.propertyeditors.CustomCollectionEditor">
<constructor-arg
index="0"><value>java.util.LinkedList</value></constructor-arg>
<constructor-arg
index="1"><value>true</value></constructor-arg>
</bean>
</entry>
</map>
</property>
</bean>
<bean
id="cidade"
class="com.targettrust.spring.collection.Cidade"
>
<property name="ruas">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
</bean>
</beans>
Código XML 2.14 Uso de PropertyEditors.
Nesse exemplo foi registrado um property editor de class, chamado:
org.springframework.beans.propertyeditors.ClassEditor, que está associado ao
tipo Class.
Esse property editor é necessário para o property editor de Collections:
org.springframework.beans.propertyeditors.CustomCollectionEditor.
O Property editor de Collections tem dois parâmetros no construtor, o
primeiro é a classe que a collection deve ser, e o segundo é um boolean indicando se
deve ser convertido para null uma coleção vazia.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-35
Spring Framework – Framework para desenvolvimento de aplicações java
Injeção entre beans colaboradores
No Spring são chamados de beans colaboradores todo objeto que é criado por
você, como por exemplo, um objeto de negócio e que deve ser injetado em outro
objeto, em síntese é o ato de injetar um pojo em outro. Não existe nada de mágico
nisso, além de simples é muito usual, talvez a funcionalidade mais simples do
container IoC do Spring, porém a mais utilizada junto com as injeções por setter. A
injeção de colaboradores é feita através de setters ou construtor como as outras
injeções vistas anteriormente.
package com.targettrust.spring.colaboradores;
public class Cidade {
private String nome;
public Cidade() {}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Override
public String toString() {
return nome;
}
}
Código 2.28 Cidade.java Classe colaboradora.
package com.targettrust.spring.colaboradores;
import java.util.List;
public class Estado {
private String sigla;
private List<Cidade> cidades;
public Estado() {}
public String getSigla() {
return sigla;
}
public void setSigla(String sigla) {
this.sigla = sigla;
}
Diego Pacheco – http://diego-pacheco.blogspot.com
2-36
Spring Framework – Framework para desenvolvimento de aplicações java
public List<Cidade> getCidades() {
return cidades;
}
public void setCidades(List<Cidade> cidades) {
this.cidades = cidades;
}
@Override
public String toString() {
return sigla + " cidades: " + cidades;
}
}
Código 2.28 Estado.java Classe que utiliza a colaboradora.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-37
Spring Framework – Framework para desenvolvimento de aplicações java
<?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-2.0.xsd"
>
<bean
id="cidA"
class="com.targettrust.spring.colaboradores.Cidade"
>
<property name="nome"><value>Porto Alegre</value></property>
</bean>
<bean
id="cidB"
class="com.targettrust.spring.colaboradores.Cidade"
>
<property name="nome"><value>Gravataí</value></property>
</bean>
<bean
id="estado"
class="com.targettrust.spring.colaboradores.Estado"
>
<property name="sigla" value="RS" />
<property name="cidades">
<list>
<ref bean="cidA" />
<ref local="cidB" />
<bean
class="com.targettrust.spring.colaboradores.Cidade">
<property name="nome" value="Canoas" />
</bean>
</list>
</property>
</bean>
</beans>
Código XML 2.15 Injeções de colaboradores.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-38
Spring Framework – Framework para desenvolvimento de aplicações java
Nesse exemplo foi injetado uma java.util.List de Cidades no objeto Estado.
Podemos reutilizar injeções com a tag ref. Quando usamos ref com bean estamos
criando a possibilidade de acessar qualquer bean do contexto do Spring em qualquer
XML de configuração. Quando utilizado o atributo local só podemos utilizar os beans
que estão no mesmo XML, se o bean em questão estiver em outro XML, um erro será
levantado. Podemos ver o resultado dessas classes em ação no teste abaixo:
package com.targettrust.spring.colaboradores;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestColaboradores {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/colaboradores/Spri
ng-beans.xml");
System.out.println(bf.getBean("estado"));
}
}
Código 2.29 TestColaboradores.java Teste de colaboradores.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-39
Spring Framework – Framework para desenvolvimento de aplicações java
Instanciando o contexto Web
O Spring tem uma factory específica para a utilização do framework em
ambiente
servlet/JEE.
É
possível
utilizar
o
listener
org.springframework.web.context.ContextLoaderListener
ou
o
Servlet
org.springframework.web.context.ContextLoaderServlet.
Basta configurar isso no web.xml de sua aplicação, conforme exemplo abaixo:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/Spring-beans.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- ou use o ContextLoaderServlet ou invés
de usar o listener
acima.
<servlet>
<servlet-name>context</servlet-name>
<servletclass>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->
</web-app>
Código XML 2.16 web.xml.
Agora é só criar um bean no Spring para podermos utilizar esse contexto web.
Nesse exemplo será criado o DateService que é um service que irá prover a data
atual. Observe o código abaixo:
package com.targettrust.spring.web;
public class DateService {
public String getDate(){
System.out.println("Provendo serviço de data");
return new java.util.Date().toString();
}
}
Código 2.23 DateService.java.
Agora é necessário fazer as configurações desse bean no contexto do Spring,
confira isso no XML abaixo:
Diego Pacheco – http://diego-pacheco.blogspot.com
2-40
Spring Framework – Framework para desenvolvimento de aplicações java
<?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-2.0.xsd"
>
<bean
id="dateService"
class="com.targettrust.spring.web.DateService"
/>
</beans>
Código XML 2.17 Spring-beans.xml.
Para testar, vamos empacotar essa aplicação em um arquivo war. Para fazer
esse teste vamos chamar o serviço do Spring através de uma página jsp. Confira o
código abaixo:
<%@page language="java" contentType="text/html; charset=ISO-8859-1"%>
<%@page
import="org.springframework.web.context.support.WebApplicationContextUtils
"%>
<%@page import="com.targettrust.spring.web.DateService"%>
<html>
<title>Spring WEB</title>
<body>
<center><h2>Exemplo de Spring com WEB-Tier</h2></center><br>
A Data atual é:
<%=((DateService)WebApplicationContextUtils.getWebApplicationContext(getSe
rvletConfig().getServletContext()).getBean("dateService")).getDate()%>
</body>
</html>
Código 2.23 index.jsp.
É usado um utilitário do Spring para acessar o contexto dele através de uma
página
jsp.
Através
da
classe
org.springframework.web.context.
support.WebApplicationContextUtils nós obtemos o contexto do Spring. Utilizamos o
método getWebApplicationContext passando como parâmetro o ServletContext.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-41
Spring Framework – Framework para desenvolvimento de aplicações java
Exercícios
1. Faça a injeção de um objeto Cliente em um Objeto Vendedor.
2. Faça a injeção de uma Lista de Alunos em um Objeto Turma.
3. Faça a injeção de um Mapa de UF com uma Lista de Cidades.
4. Faça a injeção de um UF em um objeto País através de constructor injection.
5. Faça um Serviço de Calculadora e injete funções matemáticas nesse bean.
Diego Pacheco – http://diego-pacheco.blogspot.com
2-42
Spring Framework – Framework para desenvolvimento de aplicações java
Espaço para anotações
Diego Pacheco – http://diego-pacheco.blogspot.com
2-43
Spring Framework – Framework para Desenvolvimento de Aplicações Java
3. Manipulação de Beans
Diego Pacheco – http://diego-pacheco.blogspot.com
Spring Framework – Framework para desenvolvimento de aplicações java
Objetivos
•
Conhecer os Resource Loaders do Spring;
•
Saber utilizar o init-method;
•
Saber utilizar a herança de definições de beans;
•
Saber fazer classes de validações;
•
Saber utilizar Bean Wrapper;
•
Conhecer os PostProcessors do Spring;
•
Conhecer os principais property editors;
•
Conhecer os Eventos do container;
•
Saber utilizar o PropertyPlaceholderConfigurer;
•
Saber utilizar SingletonBeanFactoryLocator;
•
Conhecer os recursos de Internacionalização.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-2
Spring Framework – Framework para desenvolvimento de aplicações java
Resource Loaders
Quando usamos arquivos de configurações como, por exemplo, xml, txt,
arquivos de imagem, properties, etc é fortemente recomendado o uso de
ResourceLoader que é uma interface do Spring que define a estratégia para
carregar arquivos. O Spring prove uma especialização dessa interface que é a classe
ResourcePatternResolver que adiciona facilidades como patterns de estilo ant,
podemos usar wild cards como, por exemplo: WEB-INF/*-context.xml. Podemos
utilizar a classe ServletContextResourceLoader que faz a busca de recursos no
ServletContext.
As
BeanFactorys
do
Spring
como,
por
exemplo:
ClassPathXmlApplicationContext implementa ResourceLoader através de classes
em sua hierarquia superior. Em síntese, as outras Beans factories do Spring também
implementam essa interface ResourceLoader.
Considerando a injeção do seguinte bean.
<property name="arquivo" value="classpath:caminho/completo/dados.txt">
Código XML 3.1 injeção de resource
Nesse código XML acima utilizando um facilitador o classpath: através dessa
diretiva, instruímos o ResourceLoader a carregar esse arquivo que esteja em
qualquer lugar no classpath. Poderíamos utilizar o facilitador file: para carregar
arquivos que não estão no classpath da aplicação. Exemplo:
<property name="arquivo" value="file:/dados/caminho/completo/da dos.txt">
Código XML 3.2 injeção de resource fora do classpath
Esse facilitador também pode ser utilizado para carregar arquivos que estão
no classpath, mas para esse caso é mais recomendado o uso de classpath:. Nesse
tipo de cenário se utiliza file: quando existem mais de um arquivo com o mesmo
nome.
Podemos utilizar wild cards no stilo ant, segue alguns exemplos:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
Código de exemplos wild cards
Diego Pacheco – http://diego-pacheco.blogspot.com
3-3
Spring Framework – Framework para desenvolvimento de aplicações java
Init-Metohd e InitializingBean
O Spring prove alguns mecanismos de call back após a inicialização de um
bean. Após o container de IoC do Spring resolver as injeções de dependências ele
prove um Call Back, ou seja, ele pode estar invocando um método em sua classe e a
partir desse método você realiza algum processamento. Essa operação pode ser
configurada através da propriedade init-method. Essa solução é elegante, pois não
gera acoplamento entre o código do Spring e seu código. Veja isso na prática no
exemplo abaixo:
package com.targettrust.spring.init;
import java.util.Date;
public class HoraCertaService {
private Date data;
private String pais;
public HoraCertaService() {
System.out.println("Criando Bean de HoraCertaService ");
}
public void preparar(){
data = new Date();
System.out.println("Ajustado a hora para o pais: " + pais);
}
@SuppressWarnings("deprecation")
public String getHoraCerta(){
return pais + " -> " + data.getHours() + ":" +
data.getMinutes() + ":" + data.getSeconds();
}
public void setPais(String pais) {
this.pais = pais;
}
}
Código 3.1 HoraCertaService.java
<?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-2.0.xsd"
>
<bean
id="horaCertaService"
class="com.targettrust.spring.init.HoraCertaService"
init-method="preparar"
>
<property name="pais" value="Brasil" />
</bean>
Diego Pacheco – http://diego-pacheco.blogspot.com
3-4
Spring Framework – Framework para desenvolvimento de aplicações java
</beans>
Código XML 3.2 injeção com uso de init-method
package com.targettrust.spring.init;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/init/Springbeans.xml");
HoraCertaService bean =
(HoraCertaService)bf.getBean("horaCertaService");
System.out.println("Hora: " + bean.getHoraCerta());
}
}
Código 3.2 Testjava
Existem outras formas de utilizar Call back no Spring, porém menos
elegantes, pois acoplam o código do Spring com o de sua aplicação. Uma
possibilidade
seria
utilizar
a
interface
org.springframework.beans.
factory.InitializingBean essa interface possui o método afterPropertiesSet(). Esse
método é invocado pela BeanFactory do Spring após todas as dependências serem
resolvidas.
Assim como existe a propriedade init-method existe a propriedade destroymethod que é um Call Back para quando o container é destruído. É possível utilizar
uma
interface
para
esse
Call
Back,
a
interface
é
org.springframework.beans.factory. DisposableBean essa interface contém o
Diego Pacheco – http://diego-pacheco.blogspot.com
3-5
Spring Framework – Framework para desenvolvimento de aplicações java
método destroy(). Esse método será invocado no momento da destruição do
contexto do Spring.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-6
Spring Framework – Framework para desenvolvimento de aplicações java
Herança de Definições
Em uma aplicação orientada a objetos utilizamos com freqüência os recursos
de herança, a partir de um objeto pai nasce um objeto filho que herda os métodos
e propriedades de seu pai. O Spring framework prove mecanismos para herança de
injeções. Considere o seguinte Service:
package com.targettrust.spring.extend;
public abstract class PessoaService {
private String nome;
private String telefone;
private String email;
public PessoaService() {}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getTelefone() {
return telefone;
}
public void setTelefone(String telefone) {
this.telefone = telefone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Código 3.3 PessoaService.java
Essa é uma Service (Classe de regra de negócios) que representa operação
sobre uma pessoa, aqui temos um exemplo simplório, não é usual ter propriedades
como nome e telefone em um Service, normalmente se utiliza isso em pojos. Mas
como exemplo de herança de definições é valido.
package com.targettrust.spring.extend;
public class PessoaFisicaService extends PessoaService {
Diego Pacheco – http://diego-pacheco.blogspot.com
3-7
Spring Framework – Framework para desenvolvimento de aplicações java
private String cpf;
public PessoaFisicaService() {}
public boolean validaCpf(){
return CpfUtils.validaCPF(cpf);
}
public void mostraPessoa(){
if (validaCpf()){
System.out.println("nome: " + getNome() +
" telefone: " + getTelefone() +
" email: " + getEmail() +
" cpf: " + cpf);
}else{
System.out.println("Essa pessoa não tem um CPF
Valido.");
}
}
public String getCpf() {
return cpf;
}
public void setCpf(String cpf) {
this.cpf = cpf;
}
}
Código 3.4 PessoaFisicaService.java
Em PessoaFisicaService adicionamos a propriedade cpf e métodos como
validaCpf e mostra pessoa, que ira mostrar a pessoa com seus dados caso o cpf seja
válido. Foi utilizada a classe CpfUtils para fazer a validação do CPF, você pode
verificar os fontes no projeto do eclipse que acompanha a apostila.
Para fazer a herança de definições no Spring é necessário existir uma
estrutura de herança. Utilizamos as propriedades abstract e parent para fazer a
herança. Veja isso na prática no XML de configurações seguinte:
<?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-2.0.xsd"
>
<bean
id="pessoaService"
class="com.targettrust.spring.extend.PessoaService"
abstract="true"
>
<property name="nome"
value="Diego" />
<property name="email"
Diego Pacheco – http://diego-pacheco.blogspot.com
3-8
Spring Framework – Framework para desenvolvimento de aplicações java
value="[email protected]" />
<property name="telefone" value="455-55-55" />
</bean>
<bean
abstract="false"
id="pessoaFisicaService"
class="com.targettrust.spring.extend.PessoaFisicaService"
parent="pessoaService"
>
<property name="cpf" value="47888971210" />
</bean>
</beans>
Código XML 3.3 injeção com uso de herança.
Para testar podemos utilizar a classe de testes a baixo:
package com.targettrust.spring.extend;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/extend/Springbeans.xml");
PessoaFisicaService bean =
(PessoaFisicaService)bf.getBean("pessoaFisicaService");
bean.mostraPessoa();
}
}
Código 3.5 Teste.java
OBS: o atributo abstract=”true” é apenas uma demarcação no Spring e não é
obrigatorio que sua classe seja abstrata.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-9
Spring Framework – Framework para desenvolvimento de aplicações java
Validação
Em uma aplicação ter injeções de dependências pode não ser suficiente, é
necessário validar. O spring prove mecanismos de validação através da interface
org.springframework.validation. Validator. Essa interface trabalha com um
objeto de erro e podemos ver um relatório de erros posteriormente. Essa interface
pode ser usada em conjunto com um outro framework do portifólio do Spring, o
Spring MVC, através de uma tag, pode mostrar os erros de validação de forma
elegante em uma pagina JSP. A Interface Validator tem os seguintes métodos:
boolean supports(Class clazz);
void validate(Object target, Errors errors);
No método supports deve-se retornar true se o validador que estamos
construindo tem suporte para o Class passado por parâmetro. Normalmente se faz
um equals aqui com o parâmetro e a classe que o validador será responsável.
O método validate irá validar os dados de fato, caso seja necessário retornar
“error”, isso será feito através do objeto de errors. Veja o exemplo prático a seguir:
package com.targettrust.spring.validate;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
public class Pessoa implements Validator{
private String nome;
private Integer idade;
public Pessoa() {}
@Override
@SuppressWarnings("unchecked")
public boolean supports(Class clazz) {
return Pessoa.class.equals(clazz);
}
@Override
public void validate(Object target, Errors errors) {
ValidationUtils.rejectIfEmpty(errors, "nome", "nome.vazio");
Pessoa p = (Pessoa) target;
if (p.getIdade() < 0) {
errors.rejectValue("idade", "valor negativo");
} else if (p.getIdade() > 120) {
errors.rejectValue("idade", "velho demais");
}
}
public String getNome() {
Diego Pacheco – http://diego-pacheco.blogspot.com
3-10
Spring Framework – Framework para desenvolvimento de aplicações java
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Integer getIdade() {
return idade;
}
public void setIdade(Integer idade) {
this.idade = idade;
}
}
Código 3.6 Pessoa.java e classe de validação
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="pessoa"
class="com.targettrust.spring.validate.Pessoa"
>
<property name="nome" value="Fulano" />
<property name="idade" value="-1" />
</bean>
</beans>
Código XML 3.4 injeção com uso de validator
package com.targettrust.spring.validate;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.validation.Errors;
public class Teste {
public static void main(String[] args) {
BeanFactory bf = new ClassPathXmlApplicationContext(
"/com/targettrust/spring/validate/Spring-beans.xml");
Pessoa p = (Pessoa) bf.getBean("pessoa");
System.out.println("Nome: " + p.getNome() + " idade: " +
p.getIdade());
Errors e = new BeanPropertyBindingResult(p,"Pessoa");
p.validate(p, e);
Diego Pacheco – http://diego-pacheco.blogspot.com
3-11
Spring Framework – Framework para desenvolvimento de aplicações java
for(Object es: e.getAllErrors()){
System.out.println(es);
}
}
}
Código 3.7 Teste.java
Nesse exemplo, a partir de uma classe Pessoa foi construído um Validator
para validar o objeto. Esse validator está na mesma classe Pessoa, seria possível
colar esse código de validação em outra classe também.
Foi utilizado uma classe utilitária do Spring que é a ValidateUtils que já tem alguns
métodos que facilitam a validação.
Para o teste foi instanciado um objeto de Erro e passado esse objeto para o
método de validação, e no final foi iterado todos os erros e mostrado no console as
mensagens de erros. Nos próximos capítulos essa questão será abordada com outra
roupagem na questão dos interceptors do Spring.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-12
Spring Framework – Framework para desenvolvimento de aplicações java
Bean Wrapper
Bean Wrapper é um recurso do Spring que funciona com Java beans como o
próprio nome já diz, Java beans é um especificação da Sun que define se um
determinado objeto deve ter um construtor vazio e métodos getters e setters de
acordo com o padrão da Sun camelCase. Essa funcionalidade é na verdade um
pattern do GOF que se chama decorator. Que tambem é conhecido como Wrapper
que significa empacotar, no caso nós temos uma camada de adiciona um
funcionalidade adicional a algo existente.
BeanWrapper é uma interface do Spring que prove funcionalidades de get e
set em propriedades e propriedades de consulta que podem determinar se a
propriedade pode ser escrita ou lida. Também possibilita setar propriedades e subpropriedades de uma profundidade ilimitada. Outra funcionalidade é adicionar
listeners para quando alguma propriedade mudar de valor.
Esse recurso pode ser utilizado para fazer manipulações com propriedades
de objetos de maneira elegante. Também é usual para fazer algum tipo de bind em
sua aplicação. Confira como codificar abaixo:
package com.targettrust.spring.beanwrapper;
public class Funcionario {
private String nome;
private Long salario;
public Funcionario() {}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Long getSalario() {
return salario;
}
public void setSalario(Long salario) {
this.salario = salario;
}
@Override
public String toString() {
return "Funcionario[ nome: " + nome +
" , salario: " + salario + " ]";
Diego Pacheco – http://diego-pacheco.blogspot.com
3-13
Spring Framework – Framework para desenvolvimento de aplicações java
}
}
Código 3.8 Funcionario.java
package com.targettrust.spring.beanwrapper;
public class Empresa {
private String nome;
private Funcionario gestor;
public Empresa() {}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public Funcionario getGestor() {
return gestor;
}
public void setGestor(Funcionario gestor) {
this.gestor = gestor;
}
@Override
public String toString() {
return "Empresa [ " + nome + " | " + gestor.toString() + "
]";
}
}
Código 3.9 Empresa.java
<?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-2.0.xsd"
>
<bean
id="gestor"
class="com.targettrust.spring.beanwrapper.Funcionario"
>
<property name="nome" value="João" />
<property name="salario" value="100" />
</bean>
<bean
id="empresa"
class="com.targettrust.spring.beanwrapper.Empresa"
>
<property name="nome"
value="CromFactory" />
<property name="gestor" ref="gestor" />
Diego Pacheco – http://diego-pacheco.blogspot.com
3-14
Spring Framework – Framework para desenvolvimento de aplicações java
</bean>
</beans>
Código XML 3.5
package com.targettrust.spring.beanwrapper;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/beanwrapper/Sprin
g-beans.xml");
System.out.println(bf.getBean("empresa"));
BeanWrapper company = new
BeanWrapperImpl((Empresa)bf.getBean("empresa"));
company.setPropertyValue("nome", "Target Trust");
// ou pode ser algo assim
PropertyValue value = new PropertyValue("nome", "Some Company
Inc.");
company.setPropertyValue(value);
BeanWrapper diego = new
BeanWrapperImpl((Funcionario)bf.getBean("gestor"));
diego.setPropertyValue("nome", "Diego Pacheco");
company.setPropertyValue("gestor",
diego.getWrappedInstance());
Long sal = (Long) company.getPropertyValue("gestor.salario");
System.out.println("Salário: " + sal);
System.out.println(company);
System.out.println(company.getWrappedInstance());
// verifica o tipo da propriedade salario
System.out.println(((BeanWrapperImpl)company).getPropertyDescriptor
("gestor.salario").getPropertyType());
diego.setPropertyValue("salario",200L);
System.out.println(diego.getPropertyValue("salario"));
}
}
Código 3.10 Teste.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-15
Spring Framework – Framework para desenvolvimento de aplicações java
No exemplo acima é criado uma instância de BeanWrapperImpl a partir do
bean empresa e outra BeanWrapperImpl a partir do bean gestor. Com os métodos
getPropertyValue e setPropertyValue podemos modificar os valores dos objetos.
Para acessar objeto “real” utilizamos o método getWrappedInstance. Outra maneira
de acessar as propriedades do objeto é através do objeto PropertyValue, porém
ainda precisamos de uma instância de BeanWrapper.
As propriedades desse objeto podem ser acessadas com ‘infinita’
profundidade, por exemplo: supondo que temos um objeto Pessoa que tem um
objeto Brinquedo que tem uma propriedade tamanho, poderíamos acessar essa
propriedade
da
seguinte
maneira:
beanWrapperInstancePessoa.getPropertyValue("brinquedo.tamanho"), supondo que
temos uma instância de BeanWrapper com a variável beanWrapperInstancePessoa.
Outros exemplos de acesso com propriedades:
Expressão
Descrição
nome
Corressponde a propriedade nome do objeto empacotado, irá
tentar executar um getNome() ou isNome()
conta.valor
Indica que no objeto corrente existe uma propriedade conta
que tem uma propriedade valor, executa algo como:
getConta().getValor()
filhos[2]
Acessa a segunda posição da propriedade filhos sendo que
filhos pode ser um array ou List ou qualquer outra collection
ordenada.
estado[poa]
Indica que está sendo acessado a entrada poa em uma Map
chamado estado.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-16
Spring Framework – Framework para desenvolvimento de aplicações java
BeanPostProcessors
Esse é um recurso para customizar beans através de call-backs. Que nada
mais são do que métodos a serem invocados após determinada operação ser
executada, também conhecidos na literatura computacional como ganchos. Você
pode utilizar esse recurso para estender as operações padrão do Spring para: lógica
de instanciação, lógica de resolução de dependências e também se necessário para
operações após o container do Spring finalizar suas criações de objetos. Você pode
configurar múltiplos BeanPostProcessors se desejar assim, é possível configurar a
ordem que cada um irá rodar a partir da propriedade order, mas isso só será possível
se você implementar a interface Ordered. Existe uma forte recomendação por parte
dos criadores do Spring que você faça essa implementação.
A atuação do BeanPostProcessors é após a criação do bean do Spring, se
desejarmos mudar sua definição é necessário utilizar BeanFactoryPostProcessor que
será abordado no próximo tópico.
Após cada criação de um bean no container o Spring estará invocando o
BeanPostProcessor, isso significa que será executado antes de qualquer método initbean.
Existe uma diferença de se usar BeanPostProcessor com BeanFactory e com
ApplicationContext, por que no caso da ApplicationContex o Spring irá descobrir
todos os BeanPostProcessors e registrar automaticamente para você, já em outra
linha, a Bean Factory não fará nada disso, devemos registrá-los manualmente.
Conforme o código abaixo:
ConfigurableBeanFactory factory = new XmlBeanFactory(new
ClassPathResource("beans.xml"));
MeuBeanPostProcessor postProcessor = new MeuBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
Código 3.11 Exemplo de registro de BeanPostProcessor.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-17
Spring Framework – Framework para desenvolvimento de aplicações java
Esse tipo de Registro não é conveniente, por causa disso que para muitas
aplicações as pessoas preferem utilizar ApplicationContex ao invés de BeanFactory.
Classes que implementam BeanPostProcessor são classes especiais, logo são
tratadas de maneira diferente pelo container. Todas as BenPostProcessors e aqueles
beans que estejam diretamente referenciados por eles serão instanciados ao startup
do Spring.
Os recursos de AOP auto-proxing são implementados como
BeanPostProcessor,
nenhum BeanPostProcessor
ou
beans diretamente
referenciados serão elegíveis para auto-proxy, ou seja, não haverá aspectos sobre
eles. O Spring irá lhe alertar sobre essa situação com uma mensagem semelhante a
essa: “Bean 'foo' is not eligible for getting processed by all BeanPostProcessors (for
example: not eligible for auto-proxying)”. Veja um exemplo prático de como utilizar
este recurso:
package com.targettrust.spring.beanpostprocessors;
public class ObjetoA {
}
Código 3.12 ObjetoA.java
package com.targettrust.spring.beanpostprocessors;
public class ObjetoB {
}
Código 3.13 ObjetoB.java
package com.targettrust.spring.beanpostprocessors;
public class ObjetoC {
}
Código 3.14 ObjetoC.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-18
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.beanpostprocessors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class LogCreationBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String
beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String
beanName)
throws BeansException {
System.out.println("Craindo bean: " + beanName);
return bean;
}
}
Código 3.15 LogCreationBeanPostProcessor.java
<?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-2.0.xsd"
default-lazy-init="false"
>
<bean
id="a"
class="com.targettrust.spring.beanpostprocessors.ObjetoA"
/>
<bean
id="b"
class="com.targettrust.spring.beanpostprocessors.ObjetoB"
/>
<bean
id="c"
class="com.targettrust.spring.beanpostprocessors.ObjetoC"
/>
<bean
class="com.targettrust.spring.beanpostprocessors.LogCreationBeanPostProce
ssor"
/>
</beans>
Código XML 3.6 Xml de configurações
Diego Pacheco – http://diego-pacheco.blogspot.com
3-19
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.beanpostprocessors;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
new
ClassPathXmlApplicationContext("/com/targettrust/spring/beanpostprocessor
s/Spring-beans.xml");
}
}
Código 3.16 Teste.java
A interface BeanPostProcessor possui dois métodos, são eles:
• postProcessBeforeInitialization
• postProcessAfterInitialization
Um dos métodos serve para efetuar operações antes da inicialização e outro
após a inicialização do bean no contexto do Spring. Ambos os métodos recebem o
objeto e seu nome por parâmetro, assim podemos aplicar algum proxy ou regra de
negócio. Aqui poderíamos utilizar um Validator conforme visto nos tópicos
anteriores e forçar a validação de determinadas propriedades.
Outra possibilidade que temos aqui graças a esse extraordinário recurso do Spring é
que podemos criar annotations personalizadas ou fazer os componentes
implementarem interfaces e com esse gancho do BeanPostProcessor podemos ler
essas informações e efetuar diversas operações que nos desperte interesse.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-20
Spring Framework – Framework para desenvolvimento de aplicações java
BeanFactoryPostProcessors
Similar ao BeanPostProcessor, porém o BeanFactoryPostProcessor consegue
ler os metadados de configuração do Spring e também mudar esses dados antes
que
o
Spring
crie
seus
beans.
Você
pode
configurar
muitos
BenFactoryPostProcessor. É possível configurar a ordem de execução dessa classe
implementando a interface Ordered. Se você deseja mudar a instância de um bean
já criado você deve utilizar o BeanPostProcessor conforme apresentando no tópico
anterior.
O
Próprio
Spring
utiliza
beanFactoryPostProcessor
como:
PropertyResourceConfigurer e PropertyPlaceholderConfigurer.
Se estamos utilizando ApplicationContext o registro é feito de forma
automática, se estivermos utilizando uma BeanFactory precisamos fazer isso de
forma manual. A Forma de fazer isso está exemplificada logo abaixo:
XmlBeanFactory factory = new XmlBeanFactory(new
FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);
Código 3.17 Exemplo de registro de BeanPostProcessor.
No código acima é criando um PropertyPlaceHolderConfigurer que é uma
implementação de BeanFactoryPostProcessor e será detalhada nos próximos
tópicos.
Veja agora um exemplo concreto de como poderia ser utilizado o
BeanFactoryPostProcessor:
package com.targettrust.spring.beanfactorypostprocessors;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DataService {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public String showSysDate(){
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.format(new Date());
Diego Pacheco – http://diego-pacheco.blogspot.com
3-21
Spring Framework – Framework para desenvolvimento de aplicações java
}
}
Código 3.18 DataService.java
package com.targettrust.spring.beanfactorypostprocessors;
import
import
import
import
java.io.FileInputStream;
java.util.Map;
java.util.Properties;
java.util.Map.Entry;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import
org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
public class DatePatternRouterBeanFactoryPostProcessor implements
BeanFactoryPostProcessor {
@Override
@SuppressWarnings("unchecked")
public void postProcessBeanFactory(ConfigurableListableBeanFactory
beanFactory) throws BeansException {
Properties p = new Properties();
try {
p.load(new
FileInputStream("./src/com/targettrust/spring/beanfactorypostprocessors/p
atterns.properties"));
System.out.println("Patterns: " + p);
} catch (Exception e) {
throw new FatalBeanException("Erro ao buscar
patterns!",e);
}
Map<Object,Object> beans =
beanFactory.getBeansOfType(DataService.class);
for(Entry<Object, Object> e: beans.entrySet()){
System.out.println("Aplicando pattern em service: " +
e);
DataService service = ((DataService)e.getValue());
service.setPattern(p.getProperty("pattern." +
service.getPattern().replace("#", "")));
}
}
}
Código 3.19 DatePatternRouterBeanFactoryPostProcessor.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-22
Spring Framework – Framework para desenvolvimento de aplicações java
<?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-2.0.xsd"
default-lazy-init="false"
>
<bean
id="brasilDateService"
class="com.targettrust.spring.beanfactorypostprocessors.DataService"
>
<property name="pattern" value="#brasil" />
</bean>
<bean
id="usDateService"
class="com.targettrust.spring.beanfactorypostprocessors.DataService"
>
<property name="pattern" value="#us" />
</bean>
<bean
class="com.targettrust.spring.beanfactorypostprocessors.DatePatternR
outerBeanFactoryPostProcessor" />
</beans>
Código XML 3.7 Xml de configurações
package com.targettrust.spring.beanfactorypostprocessors;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
ApplicationContext ap = new
ClassPathXmlApplicationContext("/com/targettrust/spring/beanfactorypostpro
cessors/Spring-beans.xml");
System.out.println("Data Brasil pattern : " +
((DataService)ap.getBean("brasilDateService")).showSysDate());
System.out.println("Data Us pattern
: " +
((DataService)ap.getBean("usDateService")).showSysDate());
}
}
Código 3.20 Teste.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-23
Spring Framework – Framework para desenvolvimento de aplicações java
A Interface BeanFactoryPostProcessor só tem um método:
• postProcessBeanFactory
Que recebe por parâmetro um ConfigurableListableBeanFactory que é a bean
factory que está sendo configurada.Com esse parâmetro podemos manipular as
informações da BeanFactory.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-24
Spring Framework – Framework para desenvolvimento de aplicações java
Property Editors
Esse recurso é utilizado largamente no Spring framework. Property Editors
têm a capacidade de converter informações em seus tipos de dados corretos, por
exemplo, imagine que gostaríamos de injetar um uma propriedade do tipo File em
um bean do Spring para tal necessidade teriamos de fazer o seguinte
procedimento:
<bean
id="txt"
class="java.io.File"
>
<constructor-arg index="0" value="C:/BOOTSECT.BAK" />
</bean>
Código XML 3.8 Injeção de File
Após isso seria possível injetar esse bean txt no bean que necessita de um
File. Porém isso é muito doloroso e nada produtivo. Não seria mais fácil se o Spring
detectar-se automaticamente uma propriedade de um bean que é um File e criasse
o File para nós? O Spring já faz isso para nós se injetarmos um caminho para uma
File ele automaticamente faz isso para nós, por que ele já tem um PropertyEditor
default que está registrado para tal trabalho. Esse Property Editor default chama-se
FileEditor. Confira os PropertyEditor disponíveis no Spring:
Property Editor
ByteArrayPropertyEditor
Explicação
Editor para arrays de bytes. Strings vão ser convertidas
em suas correspondentes representações de bytes.
ClassEditor
Faz parte de String representando classes. Quando a
classe não é encontrada é levantado um
IllegalArgumentException. Não é registrado por default.
CustomBooleanEditor
Esse property editor é para propriedades booleans.
Trabalha com os valores [ true, false, on, off, yes, no, 0,
1]
Diego Pacheco – http://diego-pacheco.blogspot.com
3-25
Spring Framework – Framework para desenvolvimento de aplicações java
CustomCollectionEditor
Editor para qualquer tipo de coleção, útil quando
precisamos alguma coleção especifica.
CustomDateEditor
Editor para java.util.Date esse editor não está registrado
por default. Precisa ser registrado com um formato de
data especifico.
CustomNumberEditor
Editor para qualquer subclass de Number como por
exemplo: Integer, Long, Float, Double. É registrado por
default.
FileEditor
Capaz de criar arquivos do tipo java.io.File e é
registrado por default.
InputStreamEditor
Através do ResouerceDitor e Resource pode instanciar
um InputStream, mas o Spring não irá fechar o Stream
para você, é utilizado por default.
LocaleEditor
Capaz de materializar objetos do tipo Locale, a partir de
uma String no formato ling_pais. Registrado por default
PatternEditor
Resolve String para o Objeto Pattern, conforme jdk 1.5.
PropertiesEditor
Converte Strings em objetos java.lang.Properties. É
registrado por default.
StringTrimmerEditor
Property Editor que aplica um trim nas Strings,
opcionalmente pode transformar uma String vazia em
null. Não registrado por default.
URLEditor
Capaz de converter uma String em um objeto URL.
Registrado por default.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-26
Spring Framework – Framework para desenvolvimento de aplicações java
O Springframework utiliza java.beans.PropertyEditorManager para gerenciar
e procurar os property editor que são necessários a ele. Esse path de procura tem
também sun.bean.editors que conta com editores como: Font, Color e a maioria
dos tipos primitivos.
A Implementação padrão dos javabeans da Sun irá automaticamente
descobrir property editor para você, mesmo que não tenha ocorrido um registro
prévio. Mas isso só irá ocorrer se o seu Property Editor estiver na mesma package
que o tipo que ele cobre e tendo o mesmo nome da Classe + o sufixo “Editor”.
Exemplo:
com
chank
pop
Foo
FooEditor
// PropertyEditor para a Classe Foo
Você pode criar seu próprio Property Editor, para isso você precisará
estender a classe PropertyEditorSupport e registrar esse custom editor criado por
você no XML do Spring. Veja o exemplo a seguir:
package com.targettrust.spring.propertyeditor;
public class Aluno {
private String nome;
public Aluno() {}
public Aluno(String nome) {
super();
this.nome = nome;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Override
public String toString() {
return nome;
}
}
Código 3.21 Aluno.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-27
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.propertyeditor;
import java.util.List;
public class Turma {
private String nome;
private List<Aluno> alunos;
public Turma() {}
public Turma(String nome, List<Aluno> alunos) {
super();
this.nome = nome;
this.alunos = alunos;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public List<Aluno> getAlunos() {
return alunos;
}
public void setAlunos(List<Aluno> alunos) {
this.alunos = alunos;
}
@Override
public String toString() {
return nome + " alunos: " + alunos.toString();
}
}
Código 3.22 Turma.java
package com.targettrust.spring.propertyeditor;
import java.beans.PropertyEditorSupport;
public class AlunoEditor extends PropertyEditorSupport{
@Override
public void setAsText(String text) throws IllegalArgumentException
{
Aluno a = new Aluno(text);
setValue(a);
}
}
Código 3.23 AlunoEditor.java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
Diego Pacheco – http://diego-pacheco.blogspot.com
3-28
Spring Framework – Framework para desenvolvimento de aplicações java
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-2.0.xsd">
<bean id="turma"
class="com.targettrust.spring.propertyeditor.Turma">
<property name="nome" value="Curso-Spring" />
<property name="alunos">
<list>
<value>Rod</value>
<value>Joe</value>
<value>Bart</value>
<value>Homer</value>
<value>Hammer</value>
</list>
</property>
</bean>
<bean id="customEditorConfigurer"
class="org.springframework.beans.factory.config.CustomEditorConfigu
rer">
<property name="customEditors">
<map>
<entry
key="com.targettrust.spring.propertyeditor.Aluno">
<bean
class="com.targettrust.spring.propertyeditor.AlunoEditor" />
</entry>
</map>
</property>
</bean>
</beans>
Código XML 3.9 Registro do property editor
Com os property editors a injeção de propriedades fica muito mais simples e
mais rápida de ser efetuada. Nesse exemplo, como o pojo Aluno está no mesmo
package do seu Editor é possivel apagar o bean customEditorCon- figurer, porque o
mecanismo padrão da Sun de java beans irá detectar para nós.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-29
Spring Framework – Framework para desenvolvimento de aplicações java
Eventos
A escuta de eventos em um objeto ApplicationContext é feita através dos
objetos ApplicationEvent e ApplicationListener. Se um bean implementa a interface
ApplicationListener é publicado no contexto do Spring toda vez que for publicado
um evento do tipo ApplicationEvent o seu bean vai ser notificado. Confira alguns
dos eventos disponíveis por padrão na ApplicationContext.
Evento
Descrição
ContextRefreshedEvent
Publicado quando a ApplicationContext é inicializado
ou atualizado, isso significa quando todos os beans
foram carregados e o Spring está pronto para ser
usado(container IoC)
ContextClosedEvent
Publicado quando a ApplicationContext é fechada,
usando o método close.
RequestHandleEvent
Um evento Específico da Web referente a uma
requisição HTTP, evento publicado após a requisição
HTTP se finalizar. Esse evento só pode ser utilizado para
aplicações Web que utilizam o DispatcherServlet do
Spring.
Os eventos no Spring são resolvidos de forma síncrona, ou seja, o Spring irá
bloquear até que todos os listeners tenham terminado suas operações. Veja como
criar um evento personalizado em sua aplicação:
package com.targettrust.spring.event;
import org.springframework.context.ApplicationEvent;
public class FeriadoEvent extends ApplicationEvent{
private String data;
private static final long serialVersionUID = 1L;
public FeriadoEvent(Object source,String data) {
super(source);
this.data = data;
}
public String getData() {
return data;
}
Diego Pacheco – http://diego-pacheco.blogspot.com
3-30
Spring Framework – Framework para desenvolvimento de aplicações java
}
Código 3.24 FeriadoEvent.java
package com.targettrust.spring.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class FeriadoListener implements ApplicationListener {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof FeriadoEvent){
FeriadoEvent fe = (FeriadoEvent)event;
System.out.println("Viva! Dia: " + fe.getData() + " é
feriado. Uhhuu!!!" );
}
}
}
Código 3.25 FeriadoListener.java
package com.targettrust.spring.event;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class RH implements ApplicationContextAware {
private ApplicationContext ac;
public void pulicarFeriados(){
ac.publishEvent(new FeriadoEvent(this,"01/01/08"));
}
@Override
public void setApplicationContext(ApplicationContext
applicationContext)
throws BeansException {
ac = applicationContext;
}
}
Código 3.26 RH.java
<?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-2.0.xsd"
>
<bean
id="rh"
class="com.targettrust.spring.event.RH"
/>
<bean
Diego Pacheco – http://diego-pacheco.blogspot.com
3-31
Spring Framework – Framework para desenvolvimento de aplicações java
id="funcionarioEsperto"
class="com.targettrust.spring.event.FeriadoListener"
/>
</beans>
Código XML 3.10 Registro do listener
package com.targettrust.spring.event;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/event/Springbeans.xml");
RH rh = (RH)ac.getBean("rh");
rh.pulicarFeriados();
}
}
Código 3.27 Teste.java
Nesse exemplo foi utilizado o FeridoEvent que é uma classe que estende
ApplicationEvent do Spring. Para tratar o evento foi criada a classe FeriadoListener
que implementa ApplicationListener com um if parta saber se o evento disparado foi
o FeriadoEvent. A Classe RH é uma ApplicationContextAware para poder publicar o
evento através do método publishEvent.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-32
Spring Framework – Framework para desenvolvimento de aplicações java
PropertyPlaceholderConfigurer
PropertyPlaceHolderConfigurer é uma forma de externalizar informação na
bean factory. Esse objeto implementa BeanFactoryPostProcessor para poder efetuar
suas modificações nos metadados do Spring. A vantagem é que podemos
externalizar nossas configurações em arquivos.proprerties e o Spring irá buscar
nesses arquivos as configurações. Muito útil para informações de ambientes como
conexões de bancos de dados, usuários, senhas e listas de e-mails, com a vantagem
de não precisar mexer no XML de definições do Spring, reduzindo assim o risco de
outros possíveis erros. É possível procurar também nas propriedades do sistema,
para isso é necessário setar o modo systemPropertiesMode.
Pode ser utilizado para substituir classes, por exemplo, podemos fazer uma
lógica que escolhe em tempo de runtime qual classe será utilizada para um
determinado bean, muito útil para fazer determinados roteamentos, para esse tipo
de situação é útil utilizar o escopo de prototype.
Para utilizar o PropertyPlaceHolderConfigurer é necessário registrá-lo no
Spring e informar a localização dos arquivos properties. Veja um exemplo concreto
abaixo:
package com.targettrust.spring.propertyplaceholderconfigurer;
public class Instrutor {
private
private
private
private
String nome;
int idade;
String time;
float altura;
public Instrutor() {}
public Instrutor(String nome, int idade, String time, float altura)
{
super();
this.nome = nome;
this.idade = idade;
this.time = time;
this.altura = altura;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getIdade() {
return idade;
Diego Pacheco – http://diego-pacheco.blogspot.com
3-33
Spring Framework – Framework para desenvolvimento de aplicações java
}
public void setIdade(int idade) {
this.idade = idade;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public float getAltura() {
return altura;
}
public void setAltura(float altura) {
this.altura = altura;
}
@Override
public String toString() {
return " nome: " + nome +
" idade: " + idade +
" altura : " + altura+
" time: " + time ;
}
}
Código 3.28 Instrutor.java
nome=deigo
idade=22
altura=1.85
Código 3.28 config.properties
<?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-2.0.xsd"
>
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholder
Configurer">
<property name="location">
<value>classpath:com/targettrust/spring/propertyplaceholderconfigur
er/config.properties</value>
</property>
<property name="properties">
<value>time=Grêmio</value>
</property>
</bean>
<bean
id="i"
Diego Pacheco – http://diego-pacheco.blogspot.com
3-34
Spring Framework – Framework para desenvolvimento de aplicações java
class="com.targettrust.spring.propertyplaceholderconfigurer.Instrut
or"
>
<property
<property
<property
<property
</bean>
name="nome"
name="idade"
name="time"
name="altura"
value="${nome}" />
value="${idade}" />
value="${time}" />
value="${altura}" />
</beans>
Código XML 3.11 Registro do PropertyPlaceHolderConfigurer
package com.targettrust.spring.propertyplaceholderconfigurer;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"/com/targettrust/spring/propertyplaceholderconfigurer/Springbeans.xml");
Instrutor i = (Instrutor)ac.getBean("i");
System.out.println("Instrutor: " + i);
}
}
Código 3.29 Teste.java
Na definição do bean PropertyPlaceHolderConfigigurer além de um conjunto
de arquivos properties é possível passar um objeto Property para ser definido no
próprio Spring em linha, como foi feito no exemplo, assim podemos mesclar
informações vindas do file system com as informações definidas nos próprios
metadados do spring.
Existe outro PropertyPlaceHolderConfigurer que é o PropertyOverride
Configurer, esse por sua vez irá saber escrever as informações dos beans, mas o
arquivo de properties deve ter o seguinte formato:
nomeBean.propriedade=valor
outronomeBean.outrapropriedade=outrovalor
maisumnomeBean.maisumapropriedade=maisumvalor
Código 3.29 config.properties para PropertyOverrideConfigurer
Diego Pacheco – http://diego-pacheco.blogspot.com
3-35
Spring Framework – Framework para desenvolvimento de aplicações java
SingletonBeanFactoryLocator
Recurso do Spring Framework para podermos carregar múltiplos arquivos de
configurações de uma só vez. É normal termos uma aplicação dividida em camadas
como persistência, negócio, utilitários, telas, testes, etc. Neste cenário dividimos as
configurações do Spring em diversos arquivos de configurações, é possível
gerenciar uma bean factory do Spring e parametrizar os arquvios de configuração
que ela irá carregar.
Esse recurso deve ser utilizado somente quando necessário, pois pode acabar
provendo acoplamento e perda de performance. Evite utilizá-lo em pequenas
aplicações. O cenário ideal de utilização é um aplicação JEE com múltiplas camadas
(layers) onde cada camada é uma bean factory distinta, nesse caso o
SingletonBeanFactoryLocator pode ser utilizado para criar uma bean factory
hierárquica com suas diversas bean factories. Os Criadores do Spring Framework
recomendam que esse recurso seja utilizado com cautela.
Para utilizar tal recurso é necessário ter um XML na raiz de seu classptah com o
seguinte nome: beanRefFactory.xml, e nesse arquivo vai estar linkado as diversas
beans factories com seus diversos XML’s. Veja o exemplo a baixo.
package com.targettrust.spring.singletonbeanfactorylocator;
public class ObjetoA {}
Código 3.29 ObjetoA.java
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="A1"
class="com.targettrust.spring.singletonbeanfactorylocator.ObjetoA"
/>
</beans>
Código XML 3.12 Spring-beans-A.xml
<?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-2.0.xsd"
Diego Pacheco – http://diego-pacheco.blogspot.com
3-36
Spring Framework – Framework para desenvolvimento de aplicações java
default-lazy-init="true"
>
<bean
id="A2"
class="com.targettrust.spring.singletonbeanfactorylocator.ObjetoA"
/>
</beans>
Código XML 3.13 Spring-beans-B.xml
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="A3"
class="com.targettrust.spring.singletonbeanfactorylocator.ObjetoA"
/>
</beans>
Código XML 3.13 Spring-beans-C.xml
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="A4"
class="com.targettrust.spring.singletonbeanfactorylocator.ObjetoA"
/>
</beans>
Código XML 3.14 Spring-beans-D.xml
<?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-2.0.xsd"
default-lazy-init="false"
>
<bean
id="beanFactoryBean"
class="org.springframework.context.support.ClassPathXmlApplicationC
ontext"
>
Diego Pacheco – http://diego-pacheco.blogspot.com
3-37
Spring Framework – Framework para desenvolvimento de aplicações java
<constructor-arg>
<list>
<value>com/targettrust/spring/singletonbeanfactorylocator/Springbeans-A.xml</value>
<value>com/targettrust/spring/singletonbeanfactorylocator/Springbeans-B.xml</value>
<value>com/targettrust/spring/singletonbeanfactorylocator/Springbeans-C.xml</value>
</list>
</constructor-arg>
</bean>
<bean
id="beanFactoryBean2"
class="org.springframework.context.support.ClassPathXmlApplicationC
ontext"
>
<constructor-arg>
<list>
<value>com/targettrust/spring/singletonbeanfactorylocator/Springbeans-D.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
Código XML 3.15 beanRefFactory.xml.xml
package com.targettrust.spring.singletonbeanfactorylocator;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import
org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
public class Teste {
public static void main(String[] args) {
BeanFactoryLocator bfl =
SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf =
bfl.useBeanFactory("beanFactoryBean");
ObjetoA a1 = (ObjetoA)bf.getFactory().getBean("A1");
ObjetoA a2 = (ObjetoA)bf.getFactory().getBean("A2");
ObjetoA a3 = (ObjetoA)bf.getFactory().getBean("A3");
bf = bfl.useBeanFactory("beanFactoryBean2");
ObjetoA a4 = (ObjetoA)bf.getFactory().getBean("A4");
System.out.println("ObjetoA
System.out.println("ObjetoA
System.out.println("ObjetoA
System.out.println("ObjetoA
Diego Pacheco – http://diego-pacheco.blogspot.com
a1:
a2:
a3:
a4:
"
"
"
"
+
+
+
+
a1);
a2);
a3);
a4);
3-38
Spring Framework – Framework para desenvolvimento de aplicações java
}
}
Código 3.30 Teste.java
Nesse exemplo existem duas bean factories: beanFactoryBean e
beanFactoryBean2 que são definidas no arquivo BeanRefFactory.xml. A primeira
bean factory tem três XMLs de configurações e a segunda tem 1 XML de
configuração.
Na classe de testes é instanciado um BeanFactoryLocator que é um singleton
e está sob o pattern de ServiceLocator. É utilizado o método useBeanFactory para
obtermos um objeto BeanFactoryReference que através do método getFactory irá
retornar a bean factory real. Quando é necessário acessar o bean A4 que está em
outra Bean Factory é necessário trocar de bean factory para isso usamos o método
useBeanFactory novamente. Se for necessário trabalhar com Application context
devemos utilizar outro Locator que é o SingletonBeanFactoryLocator.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-39
Spring Framework – Framework para desenvolvimento de aplicações java
Internacionalização
O Spring framework tem suporte a internacionalização que é a funcionalidade
de prover suporte a aplicações multi-idiomas. O objeto ApplicationContext
implementa a interfcace MessageSource através do qual prove mensagens ou
suporte i18n. Quando um ApplicationContext é levantada automaticamente ela
procura por uma fonte de mensagens (MessageSource) definida em seu contexto, o
bean que representa essa fonte de mensagem deve ter o nome messageSource, se
nenhum objeto messageSource for localizado o Spring irá usar um MessageSource
default: StaticMessageSource vazio somente para garantir o funcionamento de
outros componentes.
Atualmente o Spring prove duas implementações de messageSource, são elas:
StaticMessageSource: É utilizada programaticamente
mensagens de forma dinâmica à sua aplicação.
para
adicionar
ResourceBundleMessageSource: Mais interessante pois possui suporte a
parte de TextFormat e carrega arquivos através dos nomes base.
Para facilitar o acesso a mensagens podemos utilizar a interface
MessageSourceAware que o Spring irá utilizar para injetar o messageSource corrente
em seu bean.
Quando utilizamos esses recursos, devemos ter múltiplos arquivos de idiomas,
por exemplo, nós informaríamos o arquivo base como: mensagens no contexto do
Spring, supondo que estamos com o Locale setado para pt_BR deve existir no file
system um arquivo com o nome: mensagems_pt_BR.properties. Veja como usar esses
recursos na prática conforme mostra o exemplo a seguir:
Diego Pacheco – http://diego-pacheco.blogspot.com
3-40
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.i18n;
import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
public class Pessoa implements MessageSourceAware{
private String nome;
private int idade;
private MessageSource ms;
public Pessoa() {}
public Pessoa(String nome, int idade) {
super();
this.nome = nome;
this.idade = idade;
}
@Override
public void setMessageSource(MessageSource messageSource) {
ms = messageSource;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getIdade() {
return idade;
}
public void setIdade(int idade) {
if( idade<=0 || idade >= 120 )
throw new
IllegalArgumentException(ms.getMessage("idade.invalida",new
Object[]{idade},Locale.getDefault()));
this.idade = idade;
}
@Override
public String toString() {
return "nome: " + nome + " idade: " + idade;
}
}
Código 3.31 Pessoa.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-41
Spring Framework – Framework para desenvolvimento de aplicações java
idade.invalida=The Age: {0} is not allowed becouse is too older or is
less them 1!
Código 3.32 mensagems_en.properties
idade.invalida=A idade: {0} não é aceitável por que é muito velha ou
menor do que 1
Código 3.33 mensagems_pt_BR.properties
<?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-2.0.xsd"
>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSou
rce">
<property name="basenames">
<list>
<value>mensagems</value>
</list>
</property>
</bean>
<bean
id="pessoa"
class="com.targettrust.spring.i18n.Pessoa"
/>
</beans>
Código XML 3.16 Spring-beans.xml
package com.targettrust.spring.i18n;
import java.util.Locale;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Teste {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/i18n/Springbeans.xml");
Locale.setDefault(Locale.ENGLISH);
setIdade(ac);
Locale.setDefault(new Locale("pt","BR"));
setIdade(ac);
Diego Pacheco – http://diego-pacheco.blogspot.com
3-42
Spring Framework – Framework para desenvolvimento de aplicações java
}
private static void setIdade(ApplicationContext ac){
Pessoa p = (Pessoa)ac.getBean("pessoa");
p.setNome("Crom");
try{
p.setIdade(200);
}catch(RuntimeException re){
re.printStackTrace();
}
}
}
Código 3.34 Teste.java
Diego Pacheco – http://diego-pacheco.blogspot.com
3-43
Spring Framework – Framework para desenvolvimento de aplicações java
Exercicios
1) Crie um objeto pessoa com nome, idade e telefone.
2) Crie um validador para pessoa.
3) Invoque o validador de pessoa em um BeanPostProcessor
4)Externalize as mensagens de erro em um arquivo property e mostre mensagens
i18n caso a idade da pessoa esteja inválida.
5) Crie um property editor que seja possível passar o nome, idade e telefone da
pessoa apenas na propriedade nome e o property editor espalhará as informações
em suas propriedades corretas.
Diego Pacheco – http://diego-pacheco.blogspot.com
3-44
Spring Framework – Framework para desenvolvimento de aplicações java
Espaço para anotações
Diego Pacheco – http://diego-pacheco.blogspot.com
3-45
Spring Framework – Framework para Desenvolvimento de Aplicações Java
4. Persistência
Diego Pacheco – http://diego-pacheco.blogspot.com
Spring Framework – Framework para desenvolvimento de aplicações java
Objetivos
•
Conhecer a hierarquia de exceptions de banco do Spring;
•
Saber criar DataSource;
•
Conhecer os principais recursos do JDBCTemplate;
•
Saber utilizar o SessionFactoryBean;
•
Conhecer os principais recursos do HibernateTemplate;
•
Saber como utilizar transações declarativas.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-2
Spring Framework – Framework para desenvolvimento de aplicações java
Hierarquia de Exceptions
O Spring framework provê uma camada de acesso a dados chamada DAO support
que prove diversas facilidades para trabalhar com JDBC, Hibernate, JDO, JPA. Esse recurso
permite trocar a tecnologia de persistência com mais facilidade e menos esforço, sem a
necessidade de se preocupar com as execptions que variam de tecnologia para tecnologia.
O Spring tem sua própria árvore de exceptions traduzindo as exceptions de tecnologias
específicas como SQLException para sua própria árvore de exceptions, onde sua exception
raiz é a DataAccessException. Esses exceptions empacotam a exception raiz, assim você
não perde nenhuma mensagem original.
O Spring pode encapsular uma exception do Hibernate, por exemplo, em uma outra
exception de sua árvore, isso é igual para as exceptions do JDO e da JPA também. Este
mecanismo do Spring lhe evita a irritação de ter que tratar exceptions que você não pode
se recuperar.
Confira a árvore de exceptions do Spring na figura abaixo:
Código 4.1 Hierarquia de Exceptions do Spring
Classes abstratas do modelo de abstração DAO do Spring: Para prover um modelo
de trabalho mais fácil com todas essas tecnologias de acesso a dados (JDO, JDBC,
Hibernate, JPA) o Spring prove uma série de classes DAOs abstratas que você pode
estender. Dentre essas classes temos:
Diego Pacheco – http://diego-pacheco.blogspot.com
4-3
Spring Framework – Framework para desenvolvimento de aplicações java
JdbcDaoSupport: Super classe para accesso via JDBC, necessita um DataSource,
prove um instância de JDBCTemplate.
HibernateDaoSupport: Super classe de acesso via Hibernate, necessita uma
SessionFactory, prove uma instância de HibernateTemplate.
JdoDaoSupport:
Super
classe
de
accesso
via
JDO,
necessita
uma
JDO,
necessita
uma
PersistenceManagerFactory, prove uma instância de JdoTemplate.
JpaDaoSupport:
Super
classe
de
accesso
via
EntityManagerFactory, prove uma instância de JpaTemplate.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-4
Spring Framework – Framework para desenvolvimento de aplicações java
Acesso a dados usando JDBC
O Spring framework se encarrega de executar as tarefas de “baixo nível” da API de
JDBC. O Spring realiza as seguintes operações:
• Define os parâmetros da conexão
• Abre a conexão
• Especifica um Statement
• Prepara e executa o Statement
• Interam os resultados (se existirem)
• Faz o trabalho a cada iteração
• Processa as exceptions
• Gerencia as transações
• Fecha a conexão
Dessa forma o desenvolvedor pode trabalhar com uma camada de mais alto nível e mais
produtivas. Essa camada está dividida basicamente em quatro pacotes, core, datasource,
object e suppport que provem objetos de acesso a dados e call backs além de datasources
e facilidades para acessar stored procedures e functions de bancos.
Trabalhando com DataSources
Quando desejamos manipular dados que estão em algum banco de dados
precisamos de uma conexão com o banco, o Spring realiza essa tarefa através de um
DataSource. DataSource é parte da especificação JDBC e pode ser visto em forma de uma
connection factory. Isso permite o container esconder os problemas de controle
transacionais e pools de conexões da API do desenvolvedor. Dessa forma é possível isolar as
conexões com os bancos dos códigos dos desenvolvedores.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-5
Spring Framework – Framework para desenvolvimento de aplicações java
No Spring é possível configurar sua fonte de dados de forma que seja possível obter
o DataSource de uma fonte JNDI. Podemos utilizar um DriverManagerDataSource que é
uma simples implementação de DataSource que devemos informar o driver a ser utilizado,
conforme exemplo abaixo:
<?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-2.0.xsd"
>
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="false"
>
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:hsql://C:/db" />
<property name="username" value="sa" />
<property name="password" value=""
/>
</bean>
</beans>
XML 4.1 DriverManagerDataSource
Para criarmos esse objeto é necessário informar o driver, a url de conexão para o
banco, usuário e a senha. Nesse caso está sendo utilizado uma conexão com o banco de
dados HSQLDB. Esse DataSource não disponibiliza pools de conexões, a cada chamada será
criada uma conexão nova.
Se você deseja uma solução de connection pool out-of-the-box, deve considerar a
solução da apache o Apache DBCP, é possível utilizar esses framework em conjunto com o
Spring.
Dica: O Spring framework faz a tradução de erros de SQL Genéricos para Exceptions mais
específicas, se você desenvolve alguma regra ou processamento em stored procedures ou
functions de bancos e lavanta exceptions personalizadas no banco, podemos traduzir essas
exceptions personalizadas para exceptions do Java.
Para fazer isso é necessário herdar a classe SQLErrorCodeSQLExceptionTranslator e
implementar o método custom translate onde você irá traduzir as exceptions.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-6
Spring Framework – Framework para desenvolvimento de aplicações java
Trabalhando com JDBCTemplate
Agora vamos ver como executar querys apartir de uma DataSource e um
JDBCTemplate. JDBTemplate é um template para acesso a dados via JDBC a classe prove
várias facilidades de acesso e métodos que já entregam os dados mais lapidados. Veja
como configurar e executar um código ddl, no exemplo abaixo:
<?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-2.0.xsd"
>
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="false"
>
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:file:///C:\\target\\spring\\db" />
<property name="username"
value="sa" />
<property name="password"
value=""
/>
</bean>
<bean
id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="lazyInit" value="false" />
</bean>
</beans>
XML 4.2 Configuração de injeção do JDBCTemplate e DataSource.
A Classe JdbcTemplate tem uma série de métodos utilitários, dentre eles podemos
destacar:
• Execute (String sql): É utilizado para executar comandos ddl.
• Update (String sql,Object[] args): É utilizado para executar inserts e updates esse
método recebe um Object[] por que ele cria um PreparedStatement. Esse método
pode ser utilizado para efetuar operações de delete também.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-7
Spring Framework – Framework para desenvolvimento de aplicações java
• queryForObject (String sql,Class requiredType): Esse método executa uma query e
retorna um objeto, especificamos o tipo passando o class do tipo.
• queryForObject (String sql,RowMapper rowMapper): Essa sobre escrita desse
método possibilita buscar dados na base e converte-los já para objetos.
• queryForInt (String sql): Método que já retorna um int primitivo a partir de uma
query SQL, é muito útil quando temos que buscar apenas um valor no banco em
alguma tabela de configuração.
• queryForList (String sql): Método que executa uma query SQL e trás um java.util.List
como resultado da consulta.
A Classe JdbcTemplate possui vários overrides dos métodos de acesso a dados para as
mais diversas situaçãoes como SQL simples, PreparedStatements, RowMapper, SQL Types.
Veja um exemplo completo de acesso a dados com os principais métodos do
JdbcTemplate no código abaixo:
<?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-2.0.xsd"
>
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="false"
>
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:file:///C:\\target\\spring\\db" />
<property name="username"
value="sa" />
<property name="password"
value=""
/>
</bean>
<bean
id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="lazyInit" value="false" />
</bean>
</beans>
XML 4.3 Configuração de injeção do JDBCTemplate e DataSource.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-8
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.jdbc;
import
import
import
import
import
org.springframework.context.ApplicationContext;
org.springframework.context.support.ClassPathXmlApplicationContext;
org.springframework.jdbc.UncategorizedSQLException;
org.springframework.jdbc.core.JdbcTemplate;
org.springframework.jdbc.core.RowMapper;
public class TesteCriaTabela {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/jdbc/Springbeans.xml");
JdbcTemplate jt = (JdbcTemplate)ac.getBean("jdbcTemplate");
try{
jt.execute("create table _teste (nome varchar(50), numerox
integer); ");
}catch(UncategorizedSQLException e){
System.out.println("A Tabela já existe! ");
jt.update("delete from teste ");
}
jt.update("insert into teste (nome) values (?) ", new
Object[]{"p1"});
jt.update("insert into teste (nome) values (?) ", new
Object[]{"p3"});
jt.update("insert into teste (nome) values (?) ", new
Object[]{"p4"});
jt.update("update teste set nome = ? where nome = ?", new
Object[]{"p2","p1"});
jt.update("delete from teste where nome = 'p4' ");
System.out.println(
jt.queryForObject("select nome from teste where nome = 'p3'
", String.class)
);
ObjetoTeste ot = (ObjetoTeste) jt.queryForObject("select nome from
teste where nome = 'p2' ", new RowMapper(){
public
Object mapRow(java.sql.ResultSet rs, int rowNum) throws java.sql.SQLException {
return new ObjetoTeste(rs.getString("nome"));
}
});
System.out.println(jt.queryForList("select * from teste"));
System.out.println(ot);
}
}
Código 4.1 TesteCriaTabela.java
Diego Pacheco – http://diego-pacheco.blogspot.com
4-9
Spring Framework – Framework para desenvolvimento de aplicações java
No Exemplo acima foram definidos dois beans no contexto do Spring, o dataSource
e o jdbcTemplate, no programa java de testes foi requisitado ao Spring o bean
jdbcTemplate e a partir dele foi possivel criar tabelas com o método execute, manipular
dados com o método update e acessar dados com os métodos queryForXXX.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-10
Spring Framework – Framework para desenvolvimento de aplicações java
Session Factory Bean
O Spring prove suporte para gerenciar uma SessionFactory do Hibernate. Essa tarefa
pode ser feita através do LocalSessionFactoryBean. Esse bean necessita de uma DataSource
e de recursos de mapeamentos podendo ser um hibernate mappings ou configurações de
mapeamento feitas no próprio Spring que seram repassadas ao Hibernate. É muito comum
utilizar esse tipo de recurso em uma aplicação JEE ou desktop.
O Seguinte exemplo mostra como configurar uma SessionFactoryBean de forma
que o Spring gerencia a SessionFactory do Hibernate com o Banco de dados HSQLDB.
<?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-2.0.xsd"
>
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="false"
>
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:file:///C:\\target\\spring\\db" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean
id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>com/targettrust/spring/hibernate/Pessoa.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.PointbaseDialect
</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
</beans>
XML 4.4 Configuração de injeção do SessionFactoryBean
Diego Pacheco – http://diego-pacheco.blogspot.com
4-11
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.hibernate;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TesteSessionFactory {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/hibernate/Springbeans.xml");
SessionFactory sf = (SessionFactory)ac.getBean("sessionFactory");
System.out.println(sf.openSession());
}
}
Código 4.2 TesteSessionFactory.java
Para podermos utilizar a integração do Spring com o Hibernate, são necessários os
seguintes jars no classpath da aplicação:
• hibernate3.jar
• jta.jar
• dom4j-1.6.1.jar
• commons-logging.jar
• commons-collections.jar
• antlr-2.7.6.jar
• hsqldb.jar
Nesse exemplo foi necessário utilizar o hsqldb.jar, pois nesse jar que estão os drivers de
acesso ao banco de dados hsqldb, se você quiser utilizar outro banco de dados em sua
aplicação, você deverá trocar esse jar pelo jar apropriado para seu banco de dados.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-12
Spring Framework – Framework para desenvolvimento de aplicações java
Hibernate Template
Assim como o JdbcTemplate é o template de acesso a dados via jdbc do Spring, o
HibernateTemplate é o template de acesso a dados via Hibernate do Spring. Antes do
Spring 2, o Spring provia em seu core suporte para Hibernate 2 e Hibernate 3, a partir de
agora e das novas versões, o Spring só prove acesso ao Hibernate 3 em seu core . No
Projeto Spring Modules existe o suporte para Hibernate 2 para as aplicações mais antigas.
O HibernateTamplate prove uma série de comodidades para a utilização da API do
Hibernate, mas sempre que for necessário você pode acessar a própria API do Hibernate
através do Spring. Hibernate template vai cuidar para abrir e fechar a SessionFactory do
Hibernate para nós e automaticamente participar das transações.
É importante destacar alguns métodos importantes do HibernateTemplate como:
•
find (String hql): Esse método faz uma busca através de um HQL e retorna
uma List.
•
findByCriteria (DetachedCriteria dt): Esse método realiza uma busca no banco
de dados através de um objeto DetachedCriteria do Hibernate e retorna uma
List.
•
Delete (String hql): Método que deleta dados no banco a partir de uma query
hsql.
•
saveOrUpdate (Object entity): Método que persiste um objeto no banco de
dados. Esse método realizará um insert se a chave primária (id) for null, do
contrário ele realizará um update.
•
Get (Object entity,Serializable id): Método que busca um objeto na base a
partir do Class que representa o objeto e o id do objeto.
Você pode utilizar os call backs disponibilizados pelo Spring se quiser ter acesso à
própria SessionFactory do Hibernate, porém, com as facilidades do Spring de abrir/fechar a
Session Factory, isso pode ser feito no método execute que recebe um HibernateCallBack
que é uma interface do Spring.
Veja no exemplo abaixo a utilização desses métodos citados acima:
Diego Pacheco – http://diego-pacheco.blogspot.com
4-13
Spring Framework – Framework para desenvolvimento de aplicações java
package com.targettrust.spring.hibernate;
public class Pessoa {
private Long id;
private String nome;
private String email;
public Pessoa() {}
public Pessoa(String nome, String email) {
super();
this.nome = nome;
this.email = email;
}
public Pessoa(Long id, String nome, String email) {
super();
this.id = id;
this.nome = nome;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "nome: " + nome + ", email: " + email;
}
}
Código 4.3 Pessoa.java
Diego Pacheco – http://diego-pacheco.blogspot.com
4-14
Spring Framework – Framework para desenvolvimento de aplicações java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="com.targettrust.spring.hibernate.Pessoa"
table="pessoa">
<id name="id" column="id" type="java.lang.Long" unsaved-value="0">
<generator class="increment"/>
</id>
<property name="nome" column="nome"
type="java.lang.String"/>
<property name="email" column="email" type="java.lang.String"/>
</class>
</hibernate-mapping>
XML 4.5 Pessoa.hbm.xml
<?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-2.0.xsd"
>
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="false"
>
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url"
value="jdbc:hsqldb:file:///C:\\target\\spring\\db" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean
id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>com/targettrust/spring/hibernate/Pessoa.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop
key="hibernate.dialect">org.hibernate.dialect.PointbaseDialect</prop>
<!--<prop key="hibernate.hbm2ddl.auto">create</prop> ->
</props>
</property>
</bean>
<bean
id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate"
Diego Pacheco – http://diego-pacheco.blogspot.com
4-15
Spring Framework – Framework para desenvolvimento de aplicações java
lazy-init="false"
>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
XML 4.6 Configuração dos beans do Spring.
package com.targettrust.spring.hibernate;
import java.util.List;
import
import
import
import
import
org.hibernate.criterion.DetachedCriteria;
org.springframework.context.ApplicationContext;
org.springframework.context.support.ClassPathXmlApplicationContext;
org.springframework.dao.DataAccessException;
org.springframework.orm.hibernate3.HibernateTemplate;
public class HibernateTemplateTest {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/hibernate/Springbeans.xml");
HibernateTemplate ht =
(HibernateTemplate)ac.getBean("hibernateTemplate");
testeFind(ht);
testeDetachedCriteria(ht);
testeSave(ht);
testeDelete(ht);
testeGet(ht);
}
private static void testeFind(HibernateTemplate ht){
Object result = ht.find(" from " + Pessoa.class.getName());
System.out.println("Pessoas: " + result);
}
private static void testeDetachedCriteria(HibernateTemplate ht){
DetachedCriteria dt = DetachedCriteria.forClass(Pessoa.class);
List dtResult = ht.findByCriteria(dt);
System.out.println(dtResult);
}
private static void testeSave(HibernateTemplate ht){
Pessoa p = new Pessoa();
String nome = "PessoaHora" + System.currentTimeMillis();
p.setNome(nome);
p.setEmail("[email protected]");
ht.saveOrUpdate(p);
ht.flush();
System.out.println(ht.find(" from
where nome = '" + nome + "'"));
}
Diego Pacheco – http://diego-pacheco.blogspot.com
" + p.getClass().getName() + "
4-16
Spring Framework – Framework para desenvolvimento de aplicações java
private static void testeDelete(HibernateTemplate ht){
Pessoa p = new Pessoa();
p.setNome("Ze Moleza");
p.setEmail("[email protected]");
try{
ht.saveOrUpdate(p);
ht.flush();
System.out.println("Pessoa: " + ht.find(" from " +
Pessoa.class.getName() + " where nome = ?","Ze Moleza"));
ht.delete(p);
ht.flush();
System.out.println("Pessoa: " + ht.find(" from " +
Pessoa.class.getName() + " where nome = ?","Ze Moleza"));
}catch(DataAccessException e){
System.out.println(e.getMessage());
}
}
private static void testeGet(HibernateTemplate ht){
System.out.println("Pessoa carregada com get: " +
ht.get(Pessoa.class, 3L));
}
}
Código 4.4 HibernateTemplateTeste.java
Neste exemplo foi configurado um DataSource para o banco de dados hsqldb e
mais dois beans gerenciados pelo Spring a SessionFactoryBean e o HibernateTemplate. A
partir dessas definições foi requisitado um HibernateTemplate ao Spring pela classe de
testes.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-17
Spring Framework – Framework para desenvolvimento de aplicações java
Transações Declarativas
Para ter esse tipo de recurso é necessário ter um servidor de aplicação como, por
exemplo, JBOSS ou ORACLE IAS, mas se estou em uma aplicação java que roda fora de
uma servidor JEE? Estou fadado a trabalhar com o gerenciamento de transações em baixo
nível programaticamente? Se você usa Spring framework a resposta é não! O Spring é
capaz de fazer isso por nós e ainda mais, com Spring é possível ter transações declarativas
com aplicações JDBC.
De forma programática podemos ter controle transacional através do
TransactionTemplate do Spring que pode ser utilizado com o Hibernate.
HibernateTransactionManager é o TransactionManager do Spring para hibernate 3, esse
objeto necessita de uma SessionFactory. Com o transactionTemplate podemos executar
um
código
através
do
método
execute
que
pode
receber
um
TransactionCallBackWithoutResult para realizarmos alguma operação no banco. Apesar de
o Spring facilitar esse trabalho, ainda assim essa abordagem é custosa e pouco produtiva.
A alternativa para esse problema pode ser o suporte de transações declarativas do
Spring framework. Esse mecanismo substitui as chamadas programáticas por interceptor
AOP aliados a proxys para adicionar o controle transacional.
Dessa forma o componente pode se focar nas regras de negócio e o controle
transacional ficará isolado de forma que poderemos trocar essa implementação sem afetar
as regras de negócio da aplicação.
Com o mecanismo de transações declarativas do Spring é possível utilizar um
contexto de transação gerenciado pelo HibernateTransactionManager com uma única
SessionFactory em uma ThreadLocal e depois trocar para transações distribuídas com JPA
apenas trocando o manager de transação, sem afetar nada no seu código já escrito.
Antes do Spring 2.0 nos Springs 1.X.X era utilizado o TransactionProxyFactoryBean,
ainda é possível utilizar esse recurso, o Spring prove total compatibilidade com isso.
Existe uma grande vantagem em utilizar o HibernateTransactionManager por que
ele irá expor a transação a nível de conexão JDBC por DataSource, ou seja, se criarmos um
JdbcTemplate com o mesmo DataSource da SessionFactory do Transactionanager teremos
controle transacional entre Hibernate e JDBC de forma declarativa.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-18
Spring Framework – Framework para desenvolvimento de aplicações java
Para criarmos um controle transacional declarativo com Hibernate precisamos:
•
DataSource
•
SessionFactoryBean
•
HibernateTransactionManager
•
AOP Config
•
TxAdvice
Primeiro vamos configurar o DataSource para acesso ao banco de dados, nesse
exemplo vamos utilizar o HSQLDB.
<!-- Definição do Dataource para acesso ao banco HSQLDB -->
<bean
id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
lazy-init="false"
>
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:file:///C:\\target\\spring\\db" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
XML 4.7 DataSource
Apartir desse DataSource vamos cirar a SessionFactory do Hibernate.
<!-- Definição da SessionFactory do Hibernate -->
<bean
id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>com/targettrust/spring/transaction/Produto.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.HSQLDialect
</prop>
</props>
</property></bean>
XML 4.7 SessionFactoryBean
Diego Pacheco – http://diego-pacheco.blogspot.com
4-19
Spring Framework – Framework para desenvolvimento de aplicações java
Agora o Gerente de Transações, nesse caso será o HibernateTransactionManager.
Esse objeto depende da SessionFactory criada anteriormente.
<!-- Definição do TransactionManager, nesse caso o escolhido para a tarefa de
gerenciar as
transações foi o
org.springframework.orm.hibernate3.HibernateTransactionManager que
gerência transações entre Hibernate e JDBC pelo DataSource -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
XML 4.7 HibernateTransactionManager
Agora a configuração AOP para indicar como as classes devem ser interceptadas
pela transação declarativa e quando interceptadas que advice elas devem utilizar. Aqui
informamos que queremos interceptar todos os métodos da classe ProdutoService, não
importando o método e os parâmetros passados. Nessa configuração foi informado para
utilizar um Advice.
<!-- Definição da configuração AOP, aqui é criado um pointcut que define os
pontos do sistema
que serão interceptados, nesse caso é a execução de quaisquer métodos
do ProdutoService.
Depois ele vincula essas classes interceptadas com um advice o
txAdvice;
-->
<aop:config>
<aop:pointcut id="produtoServiceMétodos" expression="execution(*
com.targettrust.spring.transaction.ProdutoService.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="produtoServiceMetodos"
/>
</aop:config>
XML 4.7 AOP Config
No Advice estamos definindo que métodos devem ter escopo transacional de fato.
Os métodos definidos são: findAll que necessitará de uma transação ativa, se essa
transação não estiver ativa ele irá criar uma nova, esse método está marcado como
somente leitura, ou seja, ele só faz consultas na base. O outro método é o salvar* , significa
que todos os métodos que comecem com salvar serão transacionados e terão
comportamento igual ao findAll, porém esses métodos salvar podem fazer modificações
na base de dados.
<!-- Definição do Advide AOP que casa o gerente de transações com os métodos
Esse beans informa que métodos e como esses métodos devem
ser tratados pela transação -->
<tx:advice id="txAdvice" transaction-manager="txManager">
Diego Pacheco – http://diego-pacheco.blogspot.com
4-20
Spring Framework – Framework para desenvolvimento de aplicações java
<tx:attributes>
<tx:method name="salvar*" propagation="REQUIRED" />
name="findAll"
propagation="REQUIRED" read-only="true"/>
</tx:attributes></tx:advice>
<tx:method
XML 4.7 TxAdvice
Quando o método salvar do ProdutoService for invocado, o Spring irá criar uma
nova transação se não existir nenhuma ativa, poderíamos trocar essa forma de isolamento
transacional. Poderíamos usar REQUIRED_NEW que força a criação de uma nova transação
a cada chamada ao método.
O Spring faz o controle de commit e rollback baseado em exceptions, toda
exception unchecked levantada pelo componente transacionado irá demarcar a transação
para rollback, essa é uma maneira simples e eficiente de controlar commit/rollback. Se no
fim da execução de um método transacionado nenhuma exception for levantada o Spring
ira commitar. Caso alguma exception unchecked, leia-se, por exemplo, RuntimeException
for levantada o Spring irá marcar para Rollback a transação e no final sempre executará um
rollback. Podemos informar exceptions uncheckeds para o Spring e essas eceptions que
nós informarmos serão ignoradas pelo mecanismo de demarcação transacional e o Spring
não irá fazer rollback automático para essas exceptions.
Essa configuração é feita no TxAdvice dentro do TxMethod na propriedade norollback-for onde podemos informar as exceptions.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-21
Spring Framework – Framework para desenvolvimento de aplicações java
Exercícios
1) Crie um Data Source para o banco de dados HSQLDB.
2) Defina um Bean JDBCTemplate.
3) Utilize o método queryForObject e liste todos os produtos.
4) Faça um DAO que grave produtos utilizando transações declarativas e caso o produto a
ser gravado tenha valor <= 0 levante uma exception para invalidar a operação, após salveo.
Diego Pacheco – http://diego-pacheco.blogspot.com
4-22
Spring Framework – Framework para desenvolvimento de aplicações java
Espaço para anotações
Diego Pacheco – http://diego-pacheco.blogspot.com
4-23
Spring Framework – Framework para Desenvolvimento de Aplicações Java
5. Facilitadores
Diego Pacheco – http://diego-pacheco.blogspot.com
Spring Framework – Framework para desenvolvimento de aplicações java
Objetivos
•
Saber configurar e enviar e-mails;
•
Saber agendar tarefas com JDK Task;
•
Saber interceptar métodos com o AOP;
•
Saber montar um context de test com Junit;
•
Saber expor um serviço via RMI.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-2
Spring Framework – Framework para desenvolvimento de aplicações java
Envio de E-mails
O Spring framework prove facilidades para envio de e-mails. Para utilizar os
recursos de envio de e-mail do Spring devemos ter duas bibliotecas adicionais em
nosso classpath, essas bibliotecas são:
• Java Mail (mail.jar)
• JAF (activation.jar)
Java Mail é a implementação padrão da SUN para envio de emails e JAF é um
framework do Java para trabalhar com imagem JPEG. Se você baixou a distribuição
completa do Spring na pasta lib você encontrará essas bibliotecas.
A interface central para o envio de e-mails no Spring é a interface MailSender,
na classe SimpleMailMessage temos um objeto simples com getters e setters para
servir de formulário de mensagens.
O Spring prove uma hierarquia de exceptions para e-mail, facilitando e
padronizando o controle de erros sobre o envio de e-mail, as exceptions
pertencentes a esse mecanismo são:
• MailException: Exception base que todas as exceptions de envio de e-mails
estendem.
• MailAuthenticationException: Exception que é levantada se ocorer algum
erro ao fazer a autenticação no servidor.
• MailParseException: Exception que é levantada se ocorrer algum erro ao
fazer parte de alguma propriedade da mensagen.
• MailPreparationException: Exception que é levantada se ocorrer algum
erro e não for possível preparar a mensagem de e-mail, essa exception é
levantada normalmente se você está utilizando velocity e não conseguiu
iniciar a engine do velocity ou algo do gênero.
• MailSendException: Exception que é levantada se ocorrer algum erro no
momento de enviar o e-mail.
A interface JavaMailSender adiciona funcionalidades especializadas ao envio de
e-mails como por exemplo suporte a MINE para o MailSender. JavaMailSender
Diego Pacheco – http://diego-pacheco.blogspot.com
5-3
Spring Framework – Framework para desenvolvimento de aplicações java
também prove um suporte em forma de call back para a preparação de MINE
chamada MineMessagePreparator.
Agora vamos ver um exemplo prático de como enviar e-mails com Spring.
Primeiro vamos configurar um MailSender, nesse caso será o JavaMailSender, ao
definir esse bean precisamos setar as propriedades: host, password, username, onde
host é o servidor de e-mail e username e password são usuário e senha.
<bean
id="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl"
>
<property name="host"
value="host.url.com.br"
/>
<property name="password" value="senha"
/>
<property name="username" value="[email protected]" />
</bean>
XML 5.1 Definição do bean JavaMailSender
Agora vamos definir o template de mensagens de email padrão, aqui nesse
bean que é o SimpleMailMessage definimos para onde vai os e-mails através da
propriedade from e definimos o titulo do e-mail na propriedade subject.
<bean
id="templateMessage"
class="org.springframework.mail.SimpleMailMessage"
>
<property name="from"
value= "[email protected]" />
<property name="subject" value="Teste e-mails com Spring"
</bean>
/>
XML 5.2 Definição do bean templateMessage
Diego Pacheco – http://diego-pacheco.blogspot.com
5-4
Spring Framework – Framework para desenvolvimento de aplicações java
Nesse bean definimos uma mensagem de e-mail especifica, nesse caso um email apenas de testes, esse bem é construído a partir de um template que é um
outro SimpleMailMessage isso é feito via injeção de construtor, nesse bean
configuramos para onde vai o e-mail e configuramos também o texto de
mensagem, colocar esse tipo de configuração no Spring é interessante pois fica fácil
de manter e podemos reaproveitar para vários trechos do sistema que necessite
enviar esse e-mail.
<bean
id="simpleMailMessage"
class="org.springframework.mail.SimpleMailMessage"
>
<constructor-arg index="0" ref="templateMessage"
/>
<property name="to"
value="[email protected]" />
<property name="text" value=" 123 Testando... "
/>
</bean>
XML 5.3 Definição do bean simpleMailMessage
Agora vem o programa Java, que faz o envio do e-mail de fato.É requisitado
no contexto do Spring um SimpleMailMessage que é a mensagem e um MailSender
para o envio.
package com.targettrust.spring.email;
import
import
import
import
import
org.springframework.context.ApplicationContext;
org.springframework.context.support.ClassPathXmlApplicationContext;
org.springframework.mail.MailException;
org.springframework.mail.MailSender;
org.springframework.mail.SimpleMailMessage;
public class TesteEnviaEmail {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/email/Springbeans.xml");
SimpleMailMessage msg =
(SimpleMailMessage)ac.getBean("simpleMailMessage");
MailSender ms = (MailSender)ac.getBean("mailSender");
try{
ms.send(msg);
}
catch(MailException ex) {
ex.printStackTrace();
}
}
}
Diego Pacheco – http://diego-pacheco.blogspot.com
5-5
Spring Framework – Framework para desenvolvimento de aplicações java
Código 5.1 TesteEnviaEmail.java
Uma outra alternativa seria o uso de MimeMessagePreparator. Que é uma
interface de call cack utilizada para facilitar o envio de mensagem MIME. Veja como
poderíamos usar no código abaixo:
package com.targettrust.spring.email;
import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import
import
import
import
import
org.springframework.context.ApplicationContext;
org.springframework.context.support.ClassPathXmlApplicationContext;
org.springframework.mail.MailException;
org.springframework.mail.javamail.JavaMailSender;
org.springframework.mail.javamail.MimeMessagePreparator;
public class TesteMimeMessagePreparetor {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"/com/targettrust/spring/email/Spring-beans.xml");
JavaMailSender ms = (JavaMailSender)ac.getBean("mailSender");
MimeMessagePreparator preparator = new MimeMessagePreparator() {
public void prepare(MimeMessage mimeMessage) throws Exception {
mimeMessage.setRecipient(Message.RecipientType.TO,new
InternetAddress("[email protected]"));
mimeMessage.setFrom(new InternetAddress("[email protected]"));
mimeMessage.setText("Esse é um email de teste!");
}
};
try {
ms.send(preparator);
}
catch (MailException e) {
System.out.println(e.getMessage());
}
}
}
Código 5.2 TesteMimeMessagePreparator.java
Outra solução interessante seria o uso da MimeMessageHelper que abstrai e
facilita a criação de mensagens. Veja no código abaixo:
package com.targettrust.spring.email;
import javax.mail.internet.MimeMessage;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
Diego Pacheco – http://diego-pacheco.blogspot.com
5-6
Spring Framework – Framework para desenvolvimento de aplicações java
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
public class TesteMimeMessageHelper {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"/com/targettrust/spring/email/Spring-beans.xml");
JavaMailSender ms = (JavaMailSender)ac.getBean("mailSender");
try{
MimeMessage message = ms.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setFrom("[email protected]");
helper.setTo("[email protected]");
helper.setText("Email MimeMessageHelper");
ms.send(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
Código 5.3 TesteMimeMessageHelper.java
Para enviarmos anexos com o MimeMessageHelper é bem simples, basta que
quando criarmos o objeto MimeMessageHelper passemos a MimeMessage e true
para indicar que o e-mail é multipart. Depois é só adicionar os arquivos através do
método addAttachment.
package com.targettrust.spring.email;
import java.io.File;
import javax.mail.internet.MimeMessage;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
public class TesteMimeMessageHelperAtt {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"/com/targettrust/spring/email/Spring-beans.xml");
JavaMailSender ms = (JavaMailSender)ac.getBean("mailSender");
try{
MimeMessage message = ms.createMimeMessage();
Diego Pacheco – http://diego-pacheco.blogspot.com
5-7
Spring Framework – Framework para desenvolvimento de aplicações java
MimeMessageHelper helper = new
MimeMessageHelper(message,true);
helper.setFrom("[email protected]");
helper.setTo("[email protected]");
helper.setText("Email MimeMessageHelper");
FileSystemResource file = new FileSystemResource(new
File(".").getCanonicalPath() + "/build.xml");
helper.addAttachment("build.xml", file);
ms.send(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
Código 5.4 TesteMimeMessageHelper.java com envio de anexos.
Poderíamos ainda mostrar mandar um e-mail em formato html, isso nos
possibilitaria um leque muito maior de possibilidades em termos de recursos
visuais. Nesse caso poderíamos anexar uma imagem e mostrar ela no corpo do email ao invés de estar anexada a mensagem. Para isso devemos utilizar o método
addInLine e relacionar o id do in line com o id cid html. Veja no exemplo abaixo:
package com.targettrust.spring.email;
import java.io.File;
import javax.mail.internet.MimeMessage;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
public class TesteMimeMessageHelperAttImg {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(
"/com/targettrust/spring/email/Spring-beans.xml");
JavaMailSender ms = (JavaMailSender)ac.getBean("mailSender");
try{
MimeMessage message = ms.createMimeMessage();
MimeMessageHelper helper = new
MimeMessageHelper(message,true);
helper.setFrom("[email protected]");
helper.setTo("[email protected]");
helper.setText("<html><body><img
src='cid:img1'><br>Email MimeMessageHelper com suporte a imagems em
linha!</body></html>",true);
Diego Pacheco – http://diego-pacheco.blogspot.com
5-8
Spring Framework – Framework para desenvolvimento de aplicações java
FileSystemResource file = new FileSystemResource(new
File(".").getCanonicalPath() + "/imagem.jpg");
helper.addInline("img1", file);
ms.send(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
Código 5.5 TesteMimeMessageHelper.java com envio de anexos em linha html.
Importante: Para que a adição de recursos em linha funcione, você deve adicionar
primeiro o text e depois o recurso respeitando o cid. Se não, pode ser que não
funcione corretamente.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-9
Spring Framework – Framework para desenvolvimento de aplicações java
Agendamento de tarefas com JDK Task
O Spring framework provê facilidades para agendamento de tarefas
utilizando JDK Task ou se você tiver necessidades mais profundas, como manter o
agendamento mesmo que a maquina se desligue e outros recursos mais avançados
você deve utilizar o suporte do Spring ao Quartz. Nesse tópico vamos ver o
mecanismo de agendamento de tarefas com JDK Task, que pode ser utilizado em
regras de negócio ou algum requisito sistêmico como, por exemplo, envio de emails ou checagem de arquivos. Agora você verá duas maneiras de trabalhar com
Jdk Task.
A primeira envolve menos configuração XML, mas gera um acoplamento
maior com o Spring. A segunda não gera acoplamento com o Spring, porém tem
mais configuração XML.
Vamos começar com o exemplo da forma que envolve menos configuração
XML. Imagine que precisamos saber a hora a todo segundo na saída padrão, para
isso criamos um service. Esse Service deve implementar a interface TimerTask e
sobrescrever o método run.
package com.targettrust.spring.jdktask;
import java.util.Date;
import java.util.TimerTask;
public class HoraCertaService extends TimerTask{
@Override
@SuppressWarnings("deprecation")
public void run() {
System.out.println(new Date().getHours()
+ ":" +
new Date().getMinutes() + ":" +
new Date().getSeconds()
);
}
}
Código 5.6 HoraCertaService.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-10
Spring Framework – Framework para desenvolvimento de aplicações java
Agora precisamos de um ScheduledTimerTask para o agendamento da tarefa
e configurações como, atraso inicial e intervalo de tempo que a tarefa deve rodar
novamente.
<?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-2.0.xsd"
>
<bean
id="horaCertaService"
class="com.targettrust.spring.jdktask.HoraCertaService"
/>
<bean
id="scheduledTask"
class="org.springframework.scheduling.timer.ScheduledTimerTask"
lazy-init="false"
>
<!-- Espera 0 ms antes de iniciar -->
<property name="delay" value="0" />
<!-- roda de 1 em 1 segundo -->
<property name="period" value="1000" />
<!-- Ira executar a TimerTask horaCertaService -->
<property name="timerTask" ref="horaCertaService" />
</bean>
</beans>
XML 5.4 ScheduledTimerTask bean
Você pode ver que através da propriedade timerTask ligamos o nosso service
de HoraCerta com esse agendamento de tarefa.
Agora só falta injetarmos essa configuração em uma factory de
agendamento de tempo.
<bean
id="timerFactory"
class="org.springframework.scheduling.timer.TimerFactoryBean"
>
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTask" />
</list>
</property>
</bean>
XML 5.5 TimerFactoryBean bean
Diego Pacheco – http://diego-pacheco.blogspot.com
5-11
Spring Framework – Framework para desenvolvimento de aplicações java
Agora o XML completo do Spring ficará assim:
<?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-2.0.xsd"
>
<bean
id="horaCertaService"
class="com.targettrust.spring.jdktask.HoraCertaService"
/>
<bean
id="scheduledTask"
class="org.springframework.scheduling.timer.ScheduledTimerTask"
lazy-init="false"
>
<!-- Espera 0 ms antes de iniciar -->
<property name="delay" value="0" />
<!-- roda de 1 em 1 segundo -->
<property name="period" value="1000" />
<!-- Ira executar a TimerTask horaCertaService -->
<property name="timerTask" ref="horaCertaService" />
</bean>
<bean
id="timerFactory"
class="org.springframework.scheduling.timer.TimerFactoryBean"
>
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTask" />
</list>
</property>
</bean>
</beans>
XML 5.6 Spring-beans.xml
Diego Pacheco – http://diego-pacheco.blogspot.com
5-12
Spring Framework – Framework para desenvolvimento de aplicações java
Para testar basta rodar a classe de testes a baixo:
package com.targettrust.spring.jdktask;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestJdkTask {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/jdktask/Springbeans.xml");
System.out.println(ac);
}
}
Código 5.7 TestJdkTask.java
Porém essa abordagem gera acoplamento da nossa regra de negócios
(HoraCertaService) com os recursos de agendamento de tarefas(TimerTask). Agora
veremos uma abordagem que acaba com esse acoplamento, utilizando o
MethodInvokingTimerTaskFactory Bean.
Primeiro vamos refazer o HoraCertaService retirando o acoplamento com o Spring,
o código fica assim:
package com.targettrust.spring.jdktask;
import java.util.Date;
public class HoraCertaServiceNaoAcoplada {
@SuppressWarnings("deprecation")
public void showTime() {
System.out.println(new Date().getHours() + ":" +
new Date().getMinutes() + ":" +
new Date().getSeconds()
);
}
}
Código 5.8 HoraCertaServiceNaoAcoplada.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-13
Spring Framework – Framework para desenvolvimento de aplicações java
Perceba que o nome da classe foi alterado para enfatizar que esse é um
outro artefato e seu código foi modificado de fato. Agora veja como ficam as
injeções do Spring:
<?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-2.0.xsd"
>
<bean
id="horaCertaServiceNaoAcoplada"
class="com.targettrust.spring.jdktask.HoraCertaServiceNaoAcoplada"
/>
<bean
id="scheduledTask"
class="org.springframework.scheduling.timer.ScheduledTimerTask"
lazy-init="false"
>
<!-- Espera 0 ms antes de iniciar -->
<property name="delay" value="0" />
<!-- roda de 1 em 1 segundo -->
<property name="period" value="1000" />
<!-- Irá executar a TimerTask horaCertaService -->
<property name="timerTask" ref="executor" />
</bean>
<bean
id="executor"
class="org.springframework.scheduling.timer.MethodInvokingTimerTask
FactoryBean"
>
<property name="targetObject" ref="horaCertaServiceNaoAcoplada" />
<property name="targetMethod" value="showTime" />
</bean>
<bean
id="timerFactory"
class="org.springframework.scheduling.timer.TimerFactoryBean"
>
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTask" />
</list>
</property>
</bean>
</beans>
XML 5.7 Spring-beans-2.xml
Diego Pacheco – http://diego-pacheco.blogspot.com
5-14
Spring Framework – Framework para desenvolvimento de aplicações java
O Que foi feito? Foi definido um bean chamado executor e esse bean é um
MethodInvokingTimerTaskFactoryBean, onde a propriedade targetObject define
qual objeto será invocado e a propriedade targetMethod define qual método será
chamado.
Depois esse bean
timerTask=”executor”.
é
associado
ao
scheduledTask
pela
propriedade
Agora o teste. Basta rodar a classe Java abaixo:
package com.targettrust.spring.jdktask;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestJdkTaskNaoAcoplado {
public static void main(String[] args) {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/jdktask/Springbeans-2.xml");
System.out.println(ac);
}
}
Código 5.9 TestJdkTaskNaoAcoplado.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-15
Spring Framework – Framework para desenvolvimento de aplicações java
@Aspect Support
O Spring tem suporte a recursos AOP, no Spring 2.0 os recurso de aspectos
são feitos utilizando AspectJ, isso significa que os “comandos/syntax” AspectJ
funciona nas definições de pointcuts. O Mecanismo de AOP do Spring é bastante
rico, por que usa AspectJ e por que prove mais facilidades para o uso de aspectos.
Se quisermos utilizar AspectJ teríamos que criar artefatos .aj, com os recurso
do Spring, basta criarmos uma classe Java normal, que será a classe que executará
ações com os objetos interceptados e utilizarmos o conjunto de annotations do
Spring.
Agora vamos definir alguns conceitos centrais de AOP, esses termos não são
termos específicos do Spring, como a tecnologia AOP não é tão intuitiva é valido
formalizar algumas coisas.
• Aspect: Paradigma de programação que permite separar e organizar o
código conforme a importância. Um aspecto pode modificar o
comportamento de um objeto pela adição de comportamento (Advice) sobre
um ponto de execução (Join Point).
• Join Point: Representa um método em execução, as informações de um Join
Point são acessíveis no corpo de um Advice.
• Advice: Ato de pegar um Aspect em um Join Point. É uma forma de adicionar
comportamento. Existem três tipos de Advices:
• Before: Será executado antes da execução do método.
• After: Será executado depois da execução do método.
• Around: Terá poder de controlar a execução do método, podendo
proceder a execução do método ou retornar o qualquer coisa.
• Point Cut: Ato de “math” bater um Aspect com um Join Point, os Advices são
associados com Point Cuts.
• Target Object: Objeto Real. Objeto que tem um ou mais advices sobre seus
joins points.
• AOP Proxy: Objeto criado pelo framework AOP a fim de executar contratos
de aspectos, como Advices. No Spring os proxys AOP podem ser de dois
tipos: Jdk Dynamic Proxy ou CGLib proxy. Isso é transparente para o usuário.
• Weaving: É a forma de misturar os aspectos com o código target, essa
política pode ser feita em tempo de compilação com o AspectJ Compiler ou
em tempo de runtime, o Spring faz weaving em tempo de runtime.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-16
Spring Framework – Framework para desenvolvimento de aplicações java
A Compilação de AOP em Java é puramente Java, não é necessário estender a
hierarquia de class loader ou fazer qualquer configuração especial para utilizar
aspectos.
O Spring prove uma solução eficiente para a maioria dos problemas
corporativos com AOP, se você necessita de um funcionalidade de math muito
profundo ou interceptar fields a melhor escolha é utilizar AspectJ diretamente.
Para utilizarmos os recursos de @AspectJ support do Spring é necessário que os
beans estejam sobre um proxy aop, existe uma forma de fazer isso automático,
basta colocar <aop:aspectj-autoproxy/> no xml de configuração do Spring. Isso
assume que você está utilizando o schema xsd correto.
Se você estiver utilizando o schema antigo em forma de dtd por usar a seguinte
configuração: <beanclass="org.springframework.aop.aspectj.
annotation.AnnotationAwareAspectJAutoProxyCreator" />. A Utilização de
DTD no Spring 2 não é recomendada, use os recursos de xsd ao invés de dtd.
Para que você utilize esses recursos é necessário ter os seguintes jars no seu
classpath:
• aspectjweaver.jar
• aspectjrt.jar
Agora vamos a um exemplo completo de uso de @Aspect Support.
Primeiro vamos criar três Services. Cada um com um propósito distinto, neste
exemplo eles só servem para ilustrar a interceptação de objetos distintos.
Vamos criar uma interface Service, que define o que os Services devem fazer.
package com.targettrust.spring.aop;
public interface Service {
public void fazAlgo();
}
Código 5.10 Service.java
Agora as implementações dos três services:
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ServiceA implements Service{
private static final Log log = LogFactory.getLog(ServiceA.class);
@Override
public void fazAlgo() {
Diego Pacheco – http://diego-pacheco.blogspot.com
5-17
Spring Framework – Framework para desenvolvimento de aplicações java
log.info("Fiz algo do tipo A");
}
}
Código 5.11 ServiceA.java
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ServiceB implements Service{
private static final Log log = LogFactory.getLog(ServiceB.class);
@Override
public void fazAlgo() {
log.info("Fiz algo do tipo B");
}
}
Código 5.12 ServiceB.java
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class ServiceC implements Service{
private static final Log log = LogFactory.getLog(ServiceC.class);
@Override
public void fazAlgo() {
log.info("Fiz algo do tipo C");
}
}
Código 5.13 ServiceC.java
Agora vamos registrar os beans no Spring, esse registro é normal, bean id, classe
e o proxy aop.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
>
Diego Pacheco – http://diego-pacheco.blogspot.com
5-18
Spring Framework – Framework para desenvolvimento de aplicações java
<aop:aspectj-autoproxy/>
<bean
id="aspecto"
class="com.targettrust.spring.aop.Aspecto"
lazy-init="false"
/>
<bean
id="sa"
class="com.targettrust.spring.aop.ServiceA"
/>
<bean
id="sb"
class="com.targettrust.spring.aop.ServiceB"
/>
<bean
id="sc"
class="com.targettrust.spring.aop.ServiceC"
/>
<bean
id="services"
class="java.util.ArrayList"
>
<constructor-arg index="0">
<list>
<ref bean="sa" />
<ref bean="sb" />
<ref bean="sc" />
</list>
</constructor-arg>
</bean>
</beans>
XML 5.8 Spring-beans.xml
Agora a classe Aspecto. Essa classe possui a annotation @AspectJ e possui
advices de before, after e around.
package com.targettrust.spring.aop;
import
import
import
import
import
import
import
org.apache.commons.logging.Log;
org.apache.commons.logging.LogFactory;
org.aspectj.lang.ProceedingJoinPoint;
org.aspectj.lang.annotation.After;
org.aspectj.lang.annotation.Around;
org.aspectj.lang.annotation.Aspect;
org.aspectj.lang.annotation.Before;
@Aspect
public class Aspecto {
private static final Log log = LogFactory.getLog(Aspecto.class);
Diego Pacheco – http://diego-pacheco.blogspot.com
5-19
Spring Framework – Framework para desenvolvimento de aplicações java
@Before("execution(* com.targettrust.spring.aop.Service.*(..))")
public void execucaoDeFazAlgoAntes() {
log.info("To sabendo antes da execução de Service");
}
@After("execution(* com.targettrust.spring.aop.Service.*(..))")
public void execucaoDeFazAlgoDepois() {
log.info("To sabendo depois da execução de Serice");
}
@Around("execution(*
com.targettrust.spring.aop.ServiceB.faz*(..)))")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws
Throwable {
Object retVal = pjp.proceed();
log.info("To sabendo around SericeB");
return retVal;
}
}
Código 5.14 Aspecto.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-20
Spring Framework – Framework para desenvolvimento de aplicações java
Agora vamos à classe de testes:
package com.targettrust.spring.aop;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TesteAop {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
ApplicationContext ac = new
ClassPathXmlApplicationContext("/com/targettrust/spring/aop/Springbeans.xml");
List<Service> services =
(List<Service>)ac.getBean("services");
for(Service s: services){
s.fazAlgo();
}
}
}
Código 5.15 TesteAop.java
Se rodarmos esses artefatos java, teremos um retorno semelhante ao seguinte:
[INFO 16/09/2007 16:09:00.173 Aspecto.execucaoDeFazAlgoAntes(18) ] To
sabendo antes da execução de Service
[INFO 16/09/2007 16:09:00.173 ServiceA.fazAlgo(11) ] Fiz algo do tipo A
[INFO 16/09/2007 16:09:00.173 Aspecto.execucaoDeFazAlgoDepois(23) ] To
sabendo depois da execução de Serice
[INFO 16/09/2007 16:09:00.174 Aspecto.execucaoDeFazAlgoAntes(18) ] To
sabendo antes da execução de Service
[INFO 16/09/2007 16:09:00.174 ServiceB.fazAlgo(12) ] Fiz algo do tipo B
[INFO 16/09/2007 16:09:00.174 Aspecto.execucaoDeFazAlgoDepois(23) ] To
sabendo depois da execução de Serice
[INFO 16/09/2007 16:09:00.175 Aspecto.doBasicProfiling(29) ] To sabendo
around SericeB
[INFO 16/09/2007 16:09:00.175 Aspecto.execucaoDeFazAlgoAntes(18) ] To
sabendo antes da execução de Service
[INFO 16/09/2007 16:09:00.175 ServiceC.fazAlgo(12) ] Fiz algo do tipo C
[INFO 16/09/2007 16:09:00.175 Aspecto.execucaoDeFazAlgoDepois(23) ] To
sabendo depois da execução de Serice
Código 5.16 Retorno da execução do TesteAop.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-21
Spring Framework – Framework para desenvolvimento de aplicações java
Perceba que primeiro é executado um Advice antes de um Service(a, b ou c)
depois é executado o próprio service e por último um outro advice de after. Isso é
valido para os três services, mas repare que o service b retorna “Sabendo around B”
após o advice after e o retorno da execução via proceed().
O Spring ainda suporta os seguintes PointCuts:
• execution: faz math com uma determinada execução de método.
• within: faz math com métodos limitados por tipos, exemplo: execução de
somente tipos DAO within(com.xyz.app.dao..*)
• this: limita o math para quando o proxy aop é de um determinado tipo, por
exemplo this(com.xyz.app.Serializable) para pegar somente aop proxies que
implementem Serializable
• target: limita o math para quando o real target é de um determinado tipo,
semelhante ao this só que para o real target.
• args: limita o math para quando o join point tem argumentos dos tipos
especificados.
• @target: quando o real target tem uma annotation do tipo da especificada
aqui o math é feito.
• @args: quando o real target tem uma annotation e essa annotation tem os
tipos passados aqui o math é feito.
• @annotation: quando o método a ser executado tem a annotation
especificada aqui.
• @within: quando qualquer tipo de target tem a annotation especificada aqui
o math é feito.
O Spring framework também tem outros advices disponíveis, além de before,
after e around. São eles:
•
@AfterReturning: Advice que roda quando o método em execução faz
math e retorna normalmente.
•
@AfterThrowing: Advice que roda quando o método em execução faz
math e retorna uma exception do mesmo tipo da informada.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-22
Spring Framework – Framework para desenvolvimento de aplicações java
Testing Support
O Spring framework prove integração com frameworks de teste unitário
como por Junit e o TestNG. Dentre os recursos mais importantes podemos destacar
auto-wire automática para propriedades protected e rollback no final da execução.
Esse último recurso é importantíssimo, pois podemos rodar um test e no final ele
sempre dará rollback, assim não iremos sujar a base de dados.
O Spring framerwork permite o uso de frameworks de mock objects como,
por exemplo, o easy mock. Isso é muito útil, pois dessa forma podemos testar
apenas a camada de services sem persistir na camada DAO, sendo que a camada
DAO pode ser composta de mocks. Assim isolando o teste dos Services e deixando
o teste rápido e funcional.
É possível rodar testes integrados sem a necessidade de se fazer deploy no
servidor de aplicação. Assim podemos testar recursos de SQL, Hibernate e transação
sem o servidor de aplicação, isso dá melhor desempenho aos testes.
O mecanismo de test do Spring prove gerenciamento do contexto e cache,
para promover a performance.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-23
Spring Framework – Framework para desenvolvimento de aplicações java
AbstractDependencyInjectionSpringContextTests
Essa classe do Spring prove as facilidades de gerenciamento de contexto do
Spring, assim o primeiro método de test a ser executado será mais lento, porém os
outros vão ser muito mais rápidos pois utilizaram o contexto que já foi iniciado.
Para utilizar esse recurso é necessário implementar o método:
protected String[] getConfigLocations() que deve retornar um array de String
com os arquivos de configurações do Spring.
O Spring utiliza seus recursos de autoWire by type para dar produtividade
aos testes. Basta declarar um objeto e prover um setter que o Spring irá injetar
automaticamente esse objeto para você.
package com.targettrust.spring.testing;
import java.util.Date;
public class DataService {
public Date getSysDate(){
return new Date();
}
}
Código 5.17 DataService.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-24
Spring Framework – Framework para desenvolvimento de aplicações java
<?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-2.0.xsd"
default-lazy-init="true"
>
<bean
id="dataService"
class="com.targettrust.spring.testing.DataService"
/>
</beans>
XML 5.9 Spring-beans.xml
package com.targettrust.spring.testing;
import java.util.Date;
import junit.framework.Assert;
import
org.springframework.test.AbstractDependencyInjectionSpringContextTests;
public class TestDataService extends
AbstractDependencyInjectionSpringContextTests {
private DataService dataService;
public void setDataService(DataService dataService) {
this.dataService = dataService;
}
@Override
protected String[] getConfigLocations() {
return new
String[]{"classpath:com/targettrust/spring/testing/Spring-beans.xml"};
}
@SuppressWarnings("deprecation")
public void testDataDoDataService(){
Date d = dataService.getSysDate();
Date l = new Date();
Assert.assertEquals(d.getDay(),l.getDay());
Assert.assertEquals(d.getMonth(),l.getMonth());
Assert.assertEquals(d.getYear(),l.getYear());
}
}
Código 5.18 TesteDataService.java classe de teste de fato.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-25
Spring Framework – Framework para desenvolvimento de aplicações java
Podemos utilizar os recursos de injeções para testes em propriedades, assim não
é necessário métodos setters. Para isso precisamos fazer duas operações.
1ª
No
construtor
da
classe
super.setPopulateProtectedVariables(true).
de
testes
executar
2ª
O nome da variável deve ser o mesmo nome do id do bean no Spring. E deve
ser protected.
Veja o código de exemplo seguinte. Esse código utiliza o mesmo service e o
mesmo arquivo xml do exemplo anterior.
package com.targettrust.spring.testing;
import java.util.Date;
import junit.framework.Assert;
import
org.springframework.test.AbstractDependencyInjectionSpringContextTests;
public class TestDataServiceWithProtected extends
AbstractDependencyInjectionSpringContextTests {
protected DataService dataService;
public TestDataServiceWithProtected() {
super.setPopulateProtectedVariables(true);
}
@Override
protected String[] getConfigLocations() {
return new
String[]{"classpath:com/targettrust/spring/testing/Spring-beans.xml"};
}
@SuppressWarnings("deprecation")
public void testDataDoDataService(){
Date d = dataService.getSysDate();
Date l = new Date();
Assert.assertEquals(d.getDay(),l.getDay());
Assert.assertEquals(d.getMonth(),l.getMonth());
Assert.assertEquals(d.getYear(),l.getYear());
}
}
Código 5.19 TesteDataServiceWithProtected.java classe de teste de fato.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-26
Spring Framework – Framework para desenvolvimento de aplicações java
AbstractAnnotationAwareTransactionalTests
Essa classe possibilita o uso de testes transacionais e em conjunto com
annotations para os testes. As annotations suportadas são:
• @DirtiesContext: Annotation que faz o mesmo que o método setDirty isso
fará que o contexto seja recarregado nesse método.
• @ExpectedException: Annotation que sinaliza que o método deve retornar
um exception específica, se ele não retornar o teste irá falhar.
• @NotTransactionl: Indica que esse método roda fora do contexto de
transações do Spring.
• @Repeat: Essa annotation recebe um número, por exemplo, 5. O Spring irá
repetir esse teste cinco vezes.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-27
Spring Framework – Framework para desenvolvimento de aplicações java
AbstractTransactionalDataSourceSpringContextTests
Essa classe de testes é utilizada para adicionar o suporte a transações, e no
final do teste irá fazer roll back automaticamente. Se existir a necessidade de
efetuar o commit por causa de seu banco de dados, você pode executar o método
super.setComplete() no construtor, isso fará com que o commit seja executado ao
invés do rollback.
Veja como utilizar esse recurso na prática com esse teste abaixo:
package com.targettrust.spring.testing;
import org.springframework.jdbc.core.JdbcTemplate;
import
org.springframework.test.AbstractTransactionalDataSourceSpringContextTest
s;
import com.targettrust.spring.transaction.Produto;
import com.targettrust.spring.transaction.ProdutoService;
public class TesteTransactionWithRollBack extends
AbstractTransactionalDataSourceSpringContextTests {
protected ProdutoService produtoService;
protected JdbcTemplate jdbcTemplate;
public TesteTransactionWithRollBack() {
//super.setComplete();
super.setDefaultRollback(true);
super.setPopulateProtectedVariables(true);
}
@Override
protected String[] getConfigLocations() {
return new
String[]{"classpath:/com/targettrust/spring/transaction/Springbeans.xml"};
}
public void testSavePessoa() throws Exception{
Produto p = new Produto();
p.setNome("PRODUTO QUE NÃO DEVE APARECER NO BANCO DE DADOS");
p.setTipo("FANTASMA");
p.setValor(666d);
produtoService.salvar(p);
System.out.println(produtoService.findAll());
}
}
Código 5.20 TesteTransactionalWithRollBack.java classe de teste de fato.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-28
Spring Framework – Framework para desenvolvimento de aplicações java
Remoting com RMI
O Spring framework prove recursos de remoting. Imagine que você tem um
sistema construído com Spring em sua corporação e um sistema novo necessita
acessar dados do outro sistema, uma solução é expor os serviços do Spring já
existentes e assim não ter retrabalho e ter aproveitamento de código, centralização
das regras de negócio e produtividade. Esses requisitos são possiveis e fáceis de se
atingirem com os recursos de remoting do Spring.
O Spring pode expor um serviço das mais diversas maneiras como: JMS, JMX,
RMI, Http Invoker, Burlap, Hessian e até mesmo EJB. Nesse capítulo vamos estudar a
forma do Spring expor um serviço via RMI.
O RMI é uma forma de RPC só que para objetos e permite efetuarmos
chamadas remotas em aplicações desenvolvidas em Java.
A vantagem do RMI é que podemos trafegar objetos complexos entre
sistemas, sem termos muita preocupação com o protocolo.Para trafegarmos um
objeto via o remoting RMI do Spring esse objeto deve obrigatoriamente ser
Serializable.
Para fazer a exposição de um serviço do Spring via RMI basta utilizarmos o
RmiServiceExporter. Para fazer a exposição é obrigatório o uso de interfaces, deve
existir uma interface publica no serviço. Essa interface será utilizada pelo sistema
que deseja acessar os dados.
O único ponto ruim é que temos que abrir uma porta para tal operação, isso
deve ser feito com cuidado por questões de segurança.
Vamos à aplicação prática. Primeiro vamos definir uma interface de acesso, a
HoraService.
package com.targettrust.spring.remoting;
import java.util.Date;
public interface HoraService {
public Date getDate();
}
Código 5.21 HoraService.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-29
Spring Framework – Framework para desenvolvimento de aplicações java
Agora vamos fazer uma implementação de serviço padrão para essa interface.
package com.targettrust.spring.remoting;
import java.util.Calendar;
import java.util.Date;
public class HoraServiceImpl implements HoraService{
public Date getDate() {
return Calendar.getInstance().getTime();
}
}
Código 5.22 HoraServiceImpl.java
Configuração do Spring no “servidor” aplicação que expõe o Serviço para outras
aplicações acessarem.
<?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-2.0.xsd"
>
<bean
id="horaService"
class="com.targettrust.spring.remoting.HoraServiceImpl"
/>
<bean
class="org.springframework.remoting.rmi.RmiServiceExporter"
>
<property name="serviceName"
value="Target-HoraService"/>
<property name="service"
ref="horaService"/>
<property name="serviceInterface"
value="com.targettrust.spring.remoting.HoraService"/>
<property name="registryPort"
value="1199"/>
</bean>
</beans>
XML 5.10 server-beans.xml
Diego Pacheco – http://diego-pacheco.blogspot.com
5-30
Spring Framework – Framework para desenvolvimento de aplicações java
Nesse arquivo de configuração do Spring, foi registrado o service de hora, o
HoraServiceImpl. E exposto como RMI através do RmiServiceExporter esse projeto
tem quatro propriedades que devem ser injetadas, são elas:
• serviceName: Nome do Serviço que o cliente irá se conectar.
• service: Ref para o bean que é o serviço real.
• serviceInterface: Apontamento para a interface do serviço.
• registryPort: Porta na qual será disponibilizado o RMI.
Agora vamos ao programa “server” quer ficará expondo o serviço por tempo
indeterminado, para fins didáticos foi feito um while(true).
package com.targettrust.spring.remoting;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class ContextServer {
@SuppressWarnings("unused")
public static void main(String[] args) throws Throwable {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/remoting/serverbeans.xml");
while(true){
Thread.sleep(10000L);
}
}
}
Código 5.23 ContextServer.java
Agora vamos a configuração xml do cliente, que poderia ser um programa Java
com RMI normal, nesse exemplo vamos utilizar os próprios recursos do Spring para
isso.
<?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-2.0.xsd"
>
<bean
id="horaService"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean"
>
<property name="serviceUrl"
value="rmi://localhost:1199/TargetHoraService"/>
<property name="serviceInterface"
value="com.targettrust.spring.remoting.HoraService"/>
</bean>
Diego Pacheco – http://diego-pacheco.blogspot.com
5-31
Spring Framework – Framework para desenvolvimento de aplicações java
</beans>
XML 5.11 cliente-beans.xml
Diego Pacheco – http://diego-pacheco.blogspot.com
5-32
Spring Framework – Framework para desenvolvimento de aplicações java
Na configuração do Spring foi definido um bean, o bean horaService que
está vindo de um proxy remoto. Dessa forma podemos trabalhar com o serviço
normalmente, até mesmo injetá-lo em outros beans colaboradores. Para essas
operações é de suma importância a interface.
Na definição desse bean passamos dois parâmetros são eles:
• serviceURL: URL apontando para onde está o serviço RMI.
• serviceInterface: Apontando para qual interface esse serviço está
exposto.
Para finalizar o programa cliente que chama o server e testa o serviço
completo de RMI.
package com.targettrust.spring.remoting;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class ContextCliente {
@SuppressWarnings("unused")
public static void main(String[] args) throws Throwable {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/remoting/clientebeans.xml");
HoraService hs = (HoraService)ac.getBean("horaService");
System.out.println("Hora vinda do Service: " + hs.getDate());
}
}
Código 5.24 ContextCliente.java
Diego Pacheco – http://diego-pacheco.blogspot.com
5-33
Spring Framework – Framework para desenvolvimento de aplicações java
Exercícios
1) Crie um Aspecto para logar todas as chamadas aos dados de um sistema.
2) Crie um agendamento com JDK Task que de cinco em cinco segundos manda um
e-mail para uma pessoa informando se ouve alguma mudança no sistema.
3) Crie um serviço de calculadora e exporte-o via RMI, faça um programa cliente
com o suporte de Junit do Spring e suas classes de teste.
Diego Pacheco – http://diego-pacheco.blogspot.com
5-34
Spring Framework – Framework para desenvolvimento de aplicações java
Espaço para anotações
Diego Pacheco – http://diego-pacheco.blogspot.com
5-35
Download

Spring Framework (2.0) Framework para