Escolar Documentos
Profissional Documentos
Cultura Documentos
Spring Framework 20 Diego Pacheco PDF
Spring Framework 20 Diego Pacheco PDF
0)
Framework para
Desenvolvimento de Aplicaes
em Java
Diego Pacheco
Dez/2007
Diego Pacheco
Sumrio
BeanFactoryPostProcessors ............................................................................................3-21
Property Editors .................................................................................................................3-25
Eventos ....................................................................................................................................3-30
PropertyPlaceholderConfigurer .................................................................................3-33
SingletonBeanFactoryLocator ......................................................................................3-36
Internacionalizao .........................................................................................................3-40
Exercicios ..............................................................................................................................3-44
Espao para anotaes ....................................................................................................3-45
1. Introduo
Objetivos
Conhecer os conceitos bsicos;
Conhecer os principais cenrios de uso;
Prover uma viso de todo o portiflio do Spring;
Saber onde baixar o Spring;
Conhecer a estrutura de diretrios dos fontes.
Conceitos Bsicos
Esse framework foi muito bem dividido, e isso pode ser observado com
clareza na figura a baixo.
melhor programar para interfaces do que para classes, Spring reduz o custo
e a complexidade de usar interfaces para zero.
Integrao com Toplink, Hibernate, JDO, and iBATIS SQL Maps: Em termos
de resource holders, suporte a implementaes de DAOs e estratgias transacionais.
Existe um suporte de primeira classe para Hibernate com muitas facilidades
providas pelo mecanismo de IoC.
Cenrios de uso
Podemos utilizar Spring nos mais diversos cenrios, desde um simples applet
at mesmo nas mais complexas aplicaes corporativas. Um exemplo tpico de uso
do Spring em uma aplicao completa Java EE onde teremos:
No caso de sua aplicao precisar fazer algum acesso remoto o Spring prove
isso de maneira transparente e elegante.
Podemos usar Spring tambm se for necessrio fazer integrao com EJB,
possvel utilizar os recursos da camada de acesso e abstrao de EJB.
Portiflio
Spring IDE para eclipse: Plugin para o ide eclipse com facilidades para o uso
de Spring. Preove auto complete para os xmls de configurao do Spring, mdulo
visual para o Spring Web Flow, negao entre os beans do Spring, e visualizao de
recursos AOP.
Spring Batch: Prove suporte para execuo de tarefas muito longas. Suporte
a programas batch os quais processam um volume muito grande de informaes de
um banco de dados. Com suporte a agendamento automtico ou manual aps
falhas, esse projeto promove suporte de execues batch para ambientes
corporativos.
Download
O Spring Framework pode ser obtido atravs do site:
http://www.springframework.org/download existe a possibilidade de baixar
somente o framework ou baixar o framework e suas dependncias. A Verso do
Spring que ser usada nessa apostila a 2.0.6 , mas muitos itens descritos aqui so
vlido tambm para a verso 1.2.x do framework.
Estrutura de Diretrios
aspectj: Fontes dos testes dos artefatos que utilizam aspectj, aqui temos
alguns artefatos de transao feitos em aspectJ.
dist: Distribuio binrias dos fontes do Spring, aqui voc encontrar os jars
do Spring, bem como todos os jars de todos os mdulos separados.
src: Contm todos os fontes do Spring framework, caso voc precise desses
fontes para debugar o comportamento de algum cdigo do Spring.
test: Nesse diretrio 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 esto nesse
diretrio, como por exemplo, annotations.
Exerccios
2. Container IoC
Objetivos
So dois tipos de injeo que o Spring utiliza em seu container de Ioc, veja:
Desacoplamento
Para fixar melhor esse conceito considere o seguinte exemplo pratico: Imagine
que um Autor escreveu muitos livros, ento considere os seguintes pojos:
package com.targettrust.spring.bad;
import java.util.List;
public Autor() {}
package com.targettrust.spring.bad;
public Livro() {}
@Override
public String toString() {
return "titulo: " + titulo + " editor: " + editora +
" ano: " + ano;
}
}
Cdigo 2.2 Livro.java
package com.targettrust.spring.bad;
import java.util.ArrayList;
import java.util.List;
for(Livro l: livros){
if (l.getAutor().getNome().equals(nome))
achados.add(l);
}
return achados;
}
package com.targettrust.spring.bad;
autor.setNome("Diego Pacheco");
autor.listarPorNome();
}
}
Cdigo 2.4 MainTest.java
package com.targettrust.spring.bad.ok;
import java.util.List;
public Autor() {}
package com.targettrust.spring.bad.ok;
public Livro() {}
@Override
public String getNome() {
return getTitulo();
}
@Override
public String getTipo() {
return "Livro";
}
@Override
}
Cdigo 2.6 Livro.java
package com.targettrust.spring.bad.ok;
package com.targettrust.spring.bad.ok;
import java.util.List;
package com.targettrust.spring.bad.ok;
import java.util.ArrayList;
import java.util.List;
for(Publicavel p: publicaveis){
if (p.getAutor().equals(nome))
achados.add(p);
}
return achados;
}
package com.targettrust.spring.bad.ok;
autor.setNome("Rod");
autor.listarPorNome();
autor.setNome("Diego Pacheco");
autor.listarPorNome();
}
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 configuraes que podemos fazer
sobre esses beans, mas vamos comear mostrando como declarar um bean no
Spring.
</beans>
package com.targettrust.spring.primeiro;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
package com.targettrust.spring.singleton;
import java.util.ArrayList;
import java.util.List;
public class Uf {
public Uf() {
System.out.println("Inicio do processamento dos estados...");
initUfs();
}
ufs.add(new Uf("Rorima","RR"));
ufs.add(new Uf("So Paulo","SP"));
ufs.add(new Uf("Santa Catarina","SC"));
ufs.add(new Uf("Sergipe","SE"));
ufs.add(new Uf("Tocantins","TO"));
}
</beans>
package com.targettrust.spring.singleton;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
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();
}
}
Perceba que a criao dos estados ocorre somente na primeira vez, mas nas
outras vezes j est em memria, logo alm, se no fizer duas vezes o mesmo
processamento, existe um ganho de performance.
</beans>
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 so utilizados, os outros 40 beans no
vo ser instanciados, e assim evitamos um processamento desnecessrio e ganhamos
em desempenho.
<bean
id="uf"
class="com.targettrust.spring.singleton.Uf"
scope="prototype"
lazy-init="true"
/>
</beans>
</beans>
Cdigo XML 2.4 Spring-beans.xml um exemplo de default lazy initialization.
Scopo Descrio
package com.targettrust.spring.scope;
public SimpleBean() {}
@Override
public String toString() {
return super.toString() + " id: " + id;
}
}
<bean
id="beanB"
class="com.targettrust.spring.scope.SimpleBean"
scope="prototype"
/>
</beans>
package com.targettrust.spring.scope;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/scope/Spring-
beans.xml");
}
Cdigo 2.18 Teste de Scopes.
package com.targettrust.spring.scope.myscope;
public Pessoa() {
}
@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;
}
}
Cdigo 2.19 Pessoa.java.
package com.targettrust.spring.scope.myscope;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SuppressWarnings("unused")
public class TestScopes {
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());
}
}
Cdigo 2.20 Classe de testesTestScopes.java.
<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"
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>
Cdigo 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 ThreadLocalScope() {
tl = new ThreadLocal<Map<String,Object>>();
tl.set(new HashMap<String, Object>());
}
@Override
public Object get(String name, ObjectFactory objectFactory) {
synchronized(tl){
@Override
public Object remove(String name) {
synchronized(tl){
Object obj = tl.get().remove(name);
return obj;
}
}
@Override
public void registerDestructionCallback(String name, Runnable
callback){
throw new UnsupportedOperationException("Essa operao de
registerDestructionCallback, no suportada!");
}
@Override
public String getConversationId() {
return null;
}
}
<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>
Cdigo XML 2.7 Definio de scope customizado.
Essa uma das duas formas que o Spring faz injeo de dependncias, ele
utiliza um mtodo setter conforme padro da Sun e atravs desse mtodo setta os
valores no objeto em questo.
package com.targettrust.spring.setter;
public Aluno() {}
@Override
public String toString() {
return "nome: " + nome +
" idade: " + idade +
" desconto: " + desconto +
" sexo: " + sexo;
}
}
Cdigo 2.22 Aluno.java.
package com.targettrust.spring.setter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
System.out.println(bf.getBean("aluno"));
}
}
No existe nada de mgico na injeo via setter, simples, basta ter o mtodo
setter e o tipo de dado injetado ser o mesmo.
package com.targettrust.spring.constructor;
@Override
public String toString() {
return " nome: " + nome +
" idade: " + idade +
" morotista: " + cartaMorotista;
}
}
Cdigo 2.24 Pessoa.java
package com.targettrust.spring.constructor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
BeanFactory bf =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/constructor/Spring
-beans.xml");
System.out.println(bf.getBean("pessoa"));
}
}
Cdigo 2.25 TestConstructor.java Teste de construtor
Caso voc tenha um construtor que receba uma String e um nmero, o Spring
pode acabar sentando valores indesejados, para resolver esse tipo de situao,
podemos especificar o tipo do argumento do construtor, conforme exemplo de XML
abaixo.
<bean
id="animal"
class="com.targettrust.spring.constructor.Animal"
>
<constructor-arg index="1" value="Black" />
<constructor-arg index="0" value="Dog" />
</bean>
Cdigo XML 2.11 Exemplo de tipo de argumento para construtor com index.
Injeo de colees
Por deafult o Spring possui tags especficas para injeo de colees, possvel
injetar: Map, List, Properties e Set. De fato podemos injetar qualquer Collection, mas
para injetar uma coleo que no seja uma das citadas, ser necessrio usar um
Custon Property Editor. Para fazer as injees das colees nativas do Spring,
utilizamos as tags: <map/>, <list/>, <set/> e <props/>. Considerando o seguinte
exemplo:
>
<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>
</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>
Cdigo XML 2.12 Exemplo de injeo de collections.
package com.targettrust.spring.collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public Estadio() {}
@Override
public String toString() {
return " pessoas: " + pessoas + "\n" +
" cadeiras: " + cadeiras + "\n" +
" Vededores de Pipoca: " + vededoresPipoca + "\n" +
" detalhes: " + detalhes;
}
}
package com.targettrust.spring.collection;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
<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>
Cdigo XML 2.13 Outra forma de injeo de Properties.
Dica: Se for explicitamente necessrio injetar uma coleo nula, ou settar null em
alguma propriedade de algum bean do Spring, podemos utilizar a tag <null/>.
package com.targettrust.spring.collection;
import java.util.LinkedList;
public Cidade() {}
<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>
Cdigo XML 2.14 Uso de PropertyEditors.
package com.targettrust.spring.colaboradores;
public Cidade() {}
@Override
public String toString() {
return nome;
}
}
Cdigo 2.28 Cidade.java Classe colaboradora.
package com.targettrust.spring.colaboradores;
import java.util.List;
public Estado() {}
@Override
public String toString() {
return sigla + " cidades: " + cidades;
}
}
>
<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>
Cdigo XML 2.15 Injees de colaboradores.
package com.targettrust.spring.colaboradores;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>
Cdigo 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 cdigo abaixo:
package com.targettrust.spring.web;
/>
</beans>
Cdigo XML 2.17 Spring-beans.xml.
Para testar, vamos empacotar essa aplicao em um arquivo war. Para fazer
esse teste vamos chamar o servio do Spring atravs de uma pgina jsp. Confira o
cdigo abaixo:
<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>
Cdigo 2.23 index.jsp.
Exerccios
3. Manipulao de Beans
Objetivos
Resource Loaders
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
Cdigo de exemplos wild cards
Init-Metohd e InitializingBean
O Spring prove alguns mecanismos de call back aps a inicializao de um
bean. Aps o container de IoC do Spring resolver as injees de dependncias ele
prove um Call Back, ou seja, ele pode estar invocando um mtodo em sua classe e a
partir desse mtodo voc realiza algum processamento. Essa operao pode ser
configurada atravs da propriedade init-method. Essa soluo elegante, pois no
gera acoplamento entre o cdigo do Spring e seu cdigo. Veja isso na prtica no
exemplo abaixo:
package com.targettrust.spring.init;
import java.util.Date;
public HoraCertaService() {
System.out.println("Criando Bean de HoraCertaService ");
}
@SuppressWarnings("deprecation")
public String getHoraCerta(){
return pais + " -> " + data.getHours() + ":" +
data.getMinutes() + ":" + data.getSeconds();
}
</beans>
Cdigo XML 3.2 injeo com uso de init-method
package com.targettrust.spring.init;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
HoraCertaService bean =
(HoraCertaService)bf.getBean("horaCertaService");
System.out.println("Hora: " + bean.getHoraCerta());
}
}
Cdigo 3.2 Testjava
Herana de Definies
package com.targettrust.spring.extend;
public PessoaService() {}
package com.targettrust.spring.extend;
public PessoaFisicaService() {}
value="pacheco@diego.com.spring" />
<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>
Cdigo XML 3.3 injeo com uso de herana.
package com.targettrust.spring.extend;
import org.springframework.beans.factory.BeanFactory;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
PessoaFisicaService bean =
(PessoaFisicaService)bf.getBean("pessoaFisicaService");
bean.mostraPessoa();
}
}
Cdigo 3.5 Teste.java
Validao
package com.targettrust.spring.validate;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
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");
}
}
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
}
Cdigo 3.6 Pessoa.java e classe de validao
>
<property name="nome" value="Fulano" />
<property name="idade" value="-1" />
</bean>
</beans>
Cdigo XML 3.4 injeo 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;
"/com/targettrust/spring/validate/Spring-beans.xml");
}
}
Cdigo 3.7 Teste.java
Bean Wrapper
Bean Wrapper um recurso do Spring que funciona com Java beans como o
prprio nome j diz, Java beans um especificao da Sun que define se um
determinado objeto deve ter um construtor vazio e mtodos getters e setters de
acordo com o padro 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 ns temos uma camada de adiciona um
funcionalidade adicional a algo existente.
Esse recurso pode ser utilizado para fazer manipulaes com propriedades
de objetos de maneira elegante. Tambm usual para fazer algum tipo de bind em
sua aplicao. Confira como codificar abaixo:
package com.targettrust.spring.beanwrapper;
public Funcionario() {}
@Override
public String toString() {
return "Funcionario[ nome: " + nome +
" , salario: " + salario + " ]";
}
Cdigo 3.8 Funcionario.java
package com.targettrust.spring.beanwrapper;
public Empresa() {}
@Override
public String toString() {
return "Empresa [ " + nome + " | " + gestor.toString() + "
]";
}
}
Cdigo 3.9 Empresa.java
>
<property name="nome" value="Joo" />
<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" />
</bean>
</beans>
Cdigo 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;
System.out.println(bf.getBean("empresa"));
company.setPropertyValue("gestor",
diego.getWrappedInstance());
System.out.println(company);
System.out.println(company.getWrappedInstance());
System.out.println(((BeanWrapperImpl)company).getPropertyDescriptor
("gestor.salario").getPropertyType());
diego.setPropertyValue("salario",200L);
System.out.println(diego.getPropertyValue("salario"));
}
}
Cdigo 3.10 Teste.java
Expresso Descrio
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 posio 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.
BeanPostProcessors
Esse tipo de Registro no conveniente, por causa disso que para muitas
aplicaes as pessoas preferem utilizar ApplicationContex ao invs de BeanFactory.
Classes que implementam BeanPostProcessor so classes especiais, logo so
tratadas de maneira diferente pelo container. Todas as BenPostProcessors e aqueles
beans que estejam diretamente referenciados por eles sero instanciados ao startup
do Spring.
Os recursos de AOP auto-proxing so implementados como
BeanPostProcessor, nenhum BeanPostProcessor ou beans diretamente
referenciados sero elegveis para auto-proxy, ou seja, no haver aspectos sobre
eles. O Spring ir lhe alertar sobre essa situao 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 prtico de como utilizar
este recurso:
package com.targettrust.spring.beanpostprocessors;
}
Cdigo 3.12 ObjetoA.java
package com.targettrust.spring.beanpostprocessors;
}
Cdigo 3.13 ObjetoB.java
package com.targettrust.spring.beanpostprocessors;
}
Cdigo 3.14 ObjetoC.java
package com.targettrust.spring.beanpostprocessors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.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;
}
}
Cdigo 3.15 LogCreationBeanPostProcessor.java
package com.targettrust.spring.beanpostprocessors;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
BeanFactoryPostProcessors
Similar ao BeanPostProcessor, porm o BeanFactoryPostProcessor consegue
ler os metadados de configurao do Spring e tambm mudar esses dados antes
que o Spring crie seus beans. Voc pode configurar muitos
BenFactoryPostProcessor. possvel configurar a ordem de execuo dessa classe
implementando a interface Ordered. Se voc deseja mudar a instncia de um bean
j criado voc deve utilizar o BeanPostProcessor conforme apresentando no tpico
anterior. O Prprio Spring utiliza beanFactoryPostProcessor como:
PropertyResourceConfigurer e PropertyPlaceholderConfigurer.
Se estamos utilizando ApplicationContext o registro feito de forma
automtica, se estivermos utilizando uma BeanFactory precisamos fazer isso de
forma manual. A Forma de fazer isso est exemplificada logo abaixo:
cfg.postProcessBeanFactory(factory);
Cdigo 3.17 Exemplo de registro de BeanPostProcessor.
package com.targettrust.spring.beanfactorypostprocessors;
import java.text.SimpleDateFormat;
import java.util.Date;
}
}
Cdigo 3.18 DataService.java
package com.targettrust.spring.beanfactorypostprocessors;
import java.io.FileInputStream;
import java.util.Map;
import java.util.Properties;
import 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;
@Override
@SuppressWarnings("unchecked")
public void postProcessBeanFactory(ConfigurableListableBeanFactory
beanFactory) throws BeansException {
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("#", "")));
}
}
}
Cdigo 3.19 DatePatternRouterBeanFactoryPostProcessor.java
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>
Cdigo XML 3.7 Xml de configuraes
package com.targettrust.spring.beanfactorypostprocessors;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
Property Editors
<bean
id="txt"
class="java.io.File"
>
<constructor-arg index="0" value="C:/BOOTSECT.BAK" />
</bean>
Aps isso seria possvel injetar esse bean txt no bean que necessita de um
File. Porm isso muito doloroso e nada produtivo. No seria mais fcil se o Spring
detectar-se automaticamente uma propriedade de um bean que um File e criasse
o File para ns? O Spring j faz isso para ns se injetarmos um caminho para uma
File ele automaticamente faz isso para ns, por que ele j tem um PropertyEditor
default que est registrado para tal trabalho. Esse Property Editor default chama-se
FileEditor. Confira os PropertyEditor disponveis no Spring:
com
chank
pop
Foo
FooEditor // PropertyEditor para a Classe Foo
Voc pode criar seu prprio 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 Aluno() {}
@Override
public String toString() {
return nome;
}
}
Cdigo 3.21 Aluno.java
package com.targettrust.spring.propertyeditor;
import java.util.List;
public Turma() {}
@Override
public String toString() {
return nome + " alunos: " + alunos.toString();
}
}
Cdigo 3.22 Turma.java
package com.targettrust.spring.propertyeditor;
import java.beans.PropertyEditorSupport;
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>
Eventos
A escuta de eventos em um objeto ApplicationContext feita atravs 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 disponveis por padro na ApplicationContext.
Evento Descrio
package com.targettrust.spring.event;
import org.springframework.context.ApplicationEvent;
package com.targettrust.spring.event;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
package com.targettrust.spring.event;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@Override
public void setApplicationContext(ApplicationContext
applicationContext)
throws BeansException {
ac = applicationContext;
}
}
Cdigo 3.26 RH.java
/>
<bean
id="funcionarioEsperto"
class="com.targettrust.spring.event.FeriadoListener"
/>
</beans>
Cdigo XML 3.10 Registro do listener
package com.targettrust.spring.event;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
RH rh = (RH)ac.getBean("rh");
rh.pulicarFeriados();
}
}
Cdigo 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 atravs do mtodo publishEvent.
PropertyPlaceholderConfigurer
package com.targettrust.spring.propertyplaceholderconfigurer;
public Instrutor() {}
}
public void setIdade(int idade) {
this.idade = idade;
}
@Override
public String toString() {
return " nome: " + nome +
" idade: " + idade +
" altura : " + altura+
" time: " + time ;
}
}
Cdigo 3.28 Instrutor.java
nome=deigo
idade=22
altura=1.85
Cdigo 3.28 config.properties
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=Grmio</value>
</property>
</bean>
<bean
id="i"
class="com.targettrust.spring.propertyplaceholderconfigurer.Instrut
or"
>
<property name="nome" value="${nome}" />
<property name="idade" value="${idade}" />
<property name="time" value="${time}" />
<property name="altura" value="${altura}" />
</bean>
</beans>
Cdigo XML 3.11 Registro do PropertyPlaceHolderConfigurer
package com.targettrust.spring.propertyplaceholderconfigurer;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
"/com/targettrust/spring/propertyplaceholderconfigurer/Spring-
beans.xml");
Instrutor i = (Instrutor)ac.getBean("i");
System.out.println("Instrutor: " + i);
}
}
Cdigo 3.29 Teste.java
nomeBean.propriedade=valor
outronomeBean.outrapropriedade=outrovalor
maisumnomeBean.maisumapropriedade=maisumvalor
Cdigo 3.29 config.properties para PropertyOverrideConfigurer
SingletonBeanFactoryLocator
package com.targettrust.spring.singletonbeanfactorylocator;
/>
</beans>
Cdigo XML 3.12 Spring-beans-A.xml
default-lazy-init="true"
>
<bean
id="A2"
class="com.targettrust.spring.singletonbeanfactorylocator.ObjetoA"
/>
</beans>
Cdigo XML 3.13 Spring-beans-B.xml
/>
</beans>
Cdigo XML 3.13 Spring-beans-C.xml
/>
</beans>
Cdigo XML 3.14 Spring-beans-D.xml
<bean
id="beanFactoryBean"
class="org.springframework.context.support.ClassPathXmlApplicationC
ontext"
>
<constructor-arg>
<list>
<value>com/targettrust/spring/singletonbeanfactorylocator/Spring-
beans-A.xml</value>
<value>com/targettrust/spring/singletonbeanfactorylocator/Spring-
beans-B.xml</value>
<value>com/targettrust/spring/singletonbeanfactorylocator/Spring-
beans-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/Spring-
beans-D.xml</value>
</list>
</constructor-arg>
</bean>
</beans>
Cdigo 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;
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");
}
}
Cdigo 3.30 Teste.java
Internacionalizao
package com.targettrust.spring.i18n;
import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
public Pessoa() {}
@Override
public void setMessageSource(MessageSource messageSource) {
ms = messageSource;
}
@Override
public String toString() {
return "nome: " + nome + " idade: " + idade;
}
}
Cdigo 3.31 Pessoa.java
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>
Cdigo 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;
Locale.setDefault(Locale.ENGLISH);
setIdade(ac);
Locale.setDefault(new Locale("pt","BR"));
setIdade(ac);
try{
p.setIdade(200);
}catch(RuntimeException re){
re.printStackTrace();
}
}
}
Cdigo 3.34 Teste.java
Exercicios
4. Persistncia
Objetivos
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 persistncia com mais facilidade e menos esforo, sem a
necessidade de se preocupar com as execptions que variam de tecnologia para tecnologia.
O Spring tem sua prpria rvore de exceptions traduzindo as exceptions de tecnologias
especficas como SQLException para sua prpria rvore de exceptions, onde sua exception
raiz a DataAccessException. Esses exceptions empacotam a exception raiz, assim voc
no 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 tambm. Este
mecanismo do Spring lhe evita a irritao de ter que tratar exceptions que voc no pode
se recuperar.
Abre a conexo
Especifica um Statement
Processa as exceptions
Gerencia as transaes
Fecha a conexo
Dessa forma o desenvolvedor pode trabalhar com uma camada de mais alto nvel 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 alm de datasources
e facilidades para acessar stored procedures e functions de bancos.
No Spring possvel configurar sua fonte de dados de forma que seja possvel obter
o DataSource de uma fonte JNDI. Podemos utilizar um DriverManagerDataSource que
uma simples implementao de DataSource que devemos informar o driver a ser utilizado,
conforme exemplo abaixo:
</beans>
Para criarmos esse objeto necessrio informar o driver, a url de conexo para o
banco, usurio e a senha. Nesse caso est sendo utilizado uma conexo com o banco de
dados HSQLDB. Esse DataSource no disponibiliza pools de conexes, a cada chamada ser
criada uma conexo nova.
Dica: O Spring framework faz a traduo de erros de SQL Genricos para Exceptions mais
especficas, 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 necessrio herdar a classe SQLErrorCodeSQLExceptionTranslator e
implementar o mtodo custom translate onde voc ir traduzir as exceptions.
<bean
id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="lazyInit" value="false" />
</bean>
</beans>
A Classe JdbcTemplate tem uma srie de mtodos utilitrios, dentre eles podemos
destacar:
Execute (String sql): utilizado para executar comandos ddl.
Update (String sql,Object[] args): utilizado para executar inserts e updates esse
mtodo recebe um Object[] por que ele cria um PreparedStatement. Esse mtodo
pode ser utilizado para efetuar operaes de delete tambm.
queryForInt (String sql): Mtodo 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 configurao.
queryForList (String sql): Mtodo que executa uma query SQL e trs um java.util.List
como resultado da consulta.
A Classe JdbcTemplate possui vrios overrides dos mtodos de acesso a dados para as
mais diversas situaoes como SQL simples, PreparedStatements, RowMapper, SQL Types.
Veja um exemplo completo de acesso a dados com os principais mtodos do
JdbcTemplate no cdigo abaixo:
<bean
id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
lazy-init="false"
>
<property name="dataSource" ref="dataSource" />
<property name="lazyInit" value="false" />
</bean>
</beans>
package com.targettrust.spring.jdbc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.UncategorizedSQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
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 ");
}
System.out.println(
jt.queryForObject("select nome from teste where nome = 'p3'
", String.class)
);
});
System.out.println(ot);
}
}
O Spring prove suporte para gerenciar uma SessionFactory do Hibernate. Essa tarefa
pode ser feita atravs do LocalSessionFactoryBean. Esse bean necessita de uma DataSource
e de recursos de mapeamentos podendo ser um hibernate mappings ou configuraes de
mapeamento feitas no prprio Spring que seram repassadas ao Hibernate. muito comum
utilizar esse tipo de recurso em uma aplicao JEE ou desktop.
<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>
package com.targettrust.spring.hibernate;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
SessionFactory sf = (SessionFactory)ac.getBean("sessionFactory");
System.out.println(sf.openSession());
}
}
Cdigo 4.2 TesteSessionFactory.java
Nesse exemplo foi necessrio utilizar o hsqldb.jar, pois nesse jar que esto os drivers de
acesso ao banco de dados hsqldb, se voc quiser utilizar outro banco de dados em sua
aplicao, voc dever trocar esse jar pelo jar apropriado para seu banco de dados.
Hibernate Template
package com.targettrust.spring.hibernate;
public Pessoa() {}
@Override
public String toString() {
return "nome: " + nome + ", email: " + email;
}
}
Cdigo 4.3 Pessoa.java
<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"
lazy-init="false"
>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
XML 4.6 Configurao dos beans do Spring.
package com.targettrust.spring.hibernate;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateTemplate;
HibernateTemplate ht =
(HibernateTemplate)ac.getBean("hibernateTemplate");
testeFind(ht);
testeDetachedCriteria(ht);
testeSave(ht);
testeDelete(ht);
testeGet(ht);
try{
ht.saveOrUpdate(p);
ht.flush();
}catch(DataAccessException e){
System.out.println(e.getMessage());
}
}
}
Cdigo 4.4 HibernateTemplateTeste.java
Transaes Declarativas
Para ter esse tipo de recurso necessrio ter um servidor de aplicao como, por
exemplo, JBOSS ou ORACLE IAS, mas se estou em uma aplicao java que roda fora de
uma servidor JEE? Estou fadado a trabalhar com o gerenciamento de transaes em baixo
nvel programaticamente? Se voc usa Spring framework a resposta no! O Spring
capaz de fazer isso por ns e ainda mais, com Spring possvel ter transaes declarativas
com aplicaes JDBC.
De forma programtica podemos ter controle transacional atravs 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 cdigo atravs do mtodo execute que pode receber um
TransactionCallBackWithoutResult para realizarmos alguma operao 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 transaes declarativas do
Spring framework. Esse mecanismo substitui as chamadas programticas por interceptor
AOP aliados a proxys para adicionar o controle transacional.
Dessa forma o componente pode se focar nas regras de negcio e o controle
transacional ficar isolado de forma que poderemos trocar essa implementao sem afetar
as regras de negcio da aplicao.
Com o mecanismo de transaes declarativas do Spring possvel utilizar um
contexto de transao gerenciado pelo HibernateTransactionManager com uma nica
SessionFactory em uma ThreadLocal e depois trocar para transaes distribudas com JPA
apenas trocando o manager de transao, sem afetar nada no seu cdigo j escrito.
Antes do Spring 2.0 nos Springs 1.X.X era utilizado o TransactionProxyFactoryBean,
ainda possvel utilizar esse recurso, o Spring prove total compatibilidade com isso.
Existe uma grande vantagem em utilizar o HibernateTransactionManager por que
ele ir expor a transao a nvel de conexo 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.
Agora a configurao AOP para indicar como as classes devem ser interceptadas
pela transao declarativa e quando interceptadas que advice elas devem utilizar. Aqui
informamos que queremos interceptar todos os mtodos da classe ProdutoService, no
importando o mtodo e os parmetros passados. Nessa configurao foi informado para
utilizar um Advice.
No Advice estamos definindo que mtodos devem ter escopo transacional de fato.
Os mtodos definidos so: findAll que necessitar de uma transao ativa, se essa
transao no estiver ativa ele ir criar uma nova, esse mtodo est marcado como
somente leitura, ou seja, ele s faz consultas na base. O outro mtodo o salvar* , significa
que todos os mtodos que comecem com salvar sero transacionados e tero
comportamento igual ao findAll, porm esses mtodos salvar podem fazer modificaes
na base de dados.
<!-- Definio do Advide AOP que casa o gerente de transaes com os mtodos
Esse beans informa que mtodos e como esses mtodos devem
ser tratados pela transao -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="salvar*" propagation="REQUIRED" /> <tx:method
name="findAll" propagation="REQUIRED" read-only="true"/>
</tx:attributes></tx:advice>
XML 4.7 TxAdvice
Exerccios
5. Facilitadores
Objetivos
Envio de E-mails
JAF (activation.jar)
Agora vamos ver um exemplo prtico 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 so usurio 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="username@host.com.br" />
</bean>
XML 5.1 Definio do bean JavaMailSender
<bean
id="templateMessage"
class="org.springframework.mail.SimpleMailMessage"
>
<property name="from" value= "user@host.com.br" />
<property name="subject" value="Teste e-mails com Spring" />
</bean>
XML 5.2 Definio do bean templateMessage
<bean
id="simpleMailMessage"
class="org.springframework.mail.SimpleMailMessage"
>
<constructor-arg index="0" ref="templateMessage" />
<property name="to" value="dmetallica@gmail.com" />
<property name="text" value=" 123 Testando... " />
</bean>
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 org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/email/Spring-
beans.xml");
SimpleMailMessage msg =
(SimpleMailMessage)ac.getBean("simpleMailMessage");
MailSender ms = (MailSender)ac.getBean("mailSender");
try{
ms.send(msg);
}
catch(MailException ex) {
ex.printStackTrace();
}
}
}
package com.targettrust.spring.email;
import javax.mail.Message;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessagePreparator;
JavaMailSender ms = (JavaMailSender)ac.getBean("mailSender");
package com.targettrust.spring.email;
import javax.mail.internet.MimeMessage;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
"/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("form@server.com.br");
helper.setTo("dest@server.com");
helper.setText("Email MimeMessageHelper");
ms.send(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
Cdigo 5.3 TesteMimeMessageHelper.java
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;
"/com/targettrust/spring/email/Spring-beans.xml");
JavaMailSender ms = (JavaMailSender)ac.getBean("mailSender");
try{
MimeMessage message = ms.createMimeMessage();
ms.send(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
Cdigo 5.4 TesteMimeMessageHelper.java com envio de anexos.
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;
"/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("form@server.com.br");
helper.setTo("dest@server.com");
helper.setText("<html><body><img
src='cid:img1'><br>Email MimeMessageHelper com suporte a imagems em
linha!</body></html>",true);
ms.send(message);
}catch(Exception e){
e.printStackTrace();
}
}
}
Cdigo 5.5 TesteMimeMessageHelper.java com envio de anexos em linha html.
Importante: Para que a adio de recursos em linha funcione, voc deve adicionar
primeiro o text e depois o recurso respeitando o cid. Se no, pode ser que no
funcione corretamente.
package com.targettrust.spring.jdktask;
import java.util.Date;
import java.util.TimerTask;
@Override
@SuppressWarnings("deprecation")
public void run() {
System.out.println(new Date().getHours() + ":" +
new Date().getMinutes() + ":" +
new Date().getSeconds()
);
}
}
Cdigo 5.6 HoraCertaService.java
<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 atravs da propriedade timerTask ligamos o nosso service
de HoraCerta com esse agendamento de tarefa.
Agora s falta injetarmos essa configurao 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
<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
package com.targettrust.spring.jdktask;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
package com.targettrust.spring.jdktask;
import java.util.Date;
@SuppressWarnings("deprecation")
public void showTime() {
System.out.println(new Date().getHours() + ":" +
new Date().getMinutes() + ":" +
new Date().getSeconds()
);
}
}
Cdigo 5.8 HoraCertaServiceNaoAcoplada.java
Perceba que o nome da classe foi alterado para enfatizar que esse um
outro artefato e seu cdigo foi modificado de fato. Agora veja como ficam as
injees do Spring:
<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
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 mtodo ser
chamado.
Depois esse bean associado ao scheduledTask pela propriedade
timerTask=executor.
package com.targettrust.spring.jdktask;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
@Aspect Support
Vamos criar uma interface Service, que define o que os Services devem fazer.
package com.targettrust.spring.aop;
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Override
public void fazAlgo() {
log.info("Fiz algo do tipo B");
}
}
Cdigo 5.12 ServiceB.java
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@Override
public void fazAlgo() {
log.info("Fiz algo do tipo C");
}
}
Cdigo 5.13 ServiceC.java
Agora vamos registrar os beans no Spring, esse registro normal, bean id, classe
e o proxy aop.
<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
package com.targettrust.spring.aop;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class Aspecto {
@Before("execution(* com.targettrust.spring.aop.Service.*(..))")
public void execucaoDeFazAlgoAntes() {
log.info("To sabendo antes da execuo de Service");
}
@After("execution(* com.targettrust.spring.aop.Service.*(..))")
public void execucaoDeFazAlgoDepois() {
log.info("To sabendo depois da execuo 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;
}
}
Cdigo 5.14 Aspecto.java
package com.targettrust.spring.aop;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SuppressWarnings("unchecked")
public static void main(String[] args) {
ApplicationContext ac = new
ClassPathXmlApplicationContext("/com/targettrust/spring/aop/Spring-
beans.xml");
List<Service> services =
(List<Service>)ac.getBean("services");
for(Service s: services){
s.fazAlgo();
}
}
}
Cdigo 5.15 TesteAop.java
Testing Support
O Spring framework prove integrao com frameworks de teste unitrio
como por Junit e o TestNG. Dentre os recursos mais importantes podemos destacar
auto-wire automtica para propriedades protected e rollback no final da execuo.
Esse ltimo recurso importantssimo, pois podemos rodar um test e no final ele
sempre dar rollback, assim no 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 rpido e funcional.
possvel rodar testes integrados sem a necessidade de se fazer deploy no
servidor de aplicao. Assim podemos testar recursos de SQL, Hibernate e transao
sem o servidor de aplicao, isso d melhor desempenho aos testes.
O mecanismo de test do Spring prove gerenciamento do contexto e cache,
para promover a performance.
AbstractDependencyInjectionSpringContextTests
Essa classe do Spring prove as facilidades de gerenciamento de contexto do
Spring, assim o primeiro mtodo de test a ser executado ser mais lento, porm os
outros vo ser muito mais rpidos pois utilizaram o contexto que j foi iniciado.
Para utilizar esse recurso necessrio implementar o mtodo:
protected String[] getConfigLocations() que deve retornar um array de String
com os arquivos de configuraes 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;
package com.targettrust.spring.testing;
import java.util.Date;
import junit.framework.Assert;
import
org.springframework.test.AbstractDependencyInjectionSpringContextTests;
@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());
}
}
Cdigo 5.18 TesteDataService.java classe de teste de fato.
package com.targettrust.spring.testing;
import java.util.Date;
import junit.framework.Assert;
import
org.springframework.test.AbstractDependencyInjectionSpringContextTests;
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());
}
}
Cdigo 5.19 TesteDataServiceWithProtected.java classe de teste de fato.
AbstractAnnotationAwareTransactionalTests
AbstractTransactionalDataSourceSpringContextTests
Essa classe de testes utilizada para adicionar o suporte a transaes, 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 mtodo
super.setComplete() no construtor, isso far com que o commit seja executado ao
invs do rollback.
Veja como utilizar esse recurso na prtica 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 TesteTransactionWithRollBack() {
//super.setComplete();
super.setDefaultRollback(true);
super.setPopulateProtectedVariables(true);
}
@Override
protected String[] getConfigLocations() {
return new
String[]{"classpath:/com/targettrust/spring/transaction/Spring-
beans.xml"};
}
produtoService.salvar(p);
System.out.println(produtoService.findAll());
}
package com.targettrust.spring.remoting;
import java.util.Date;
Agora vamos fazer uma implementao de servio padro para essa interface.
package com.targettrust.spring.remoting;
import java.util.Calendar;
import java.util.Date;
<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
package com.targettrust.spring.remoting;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
@SuppressWarnings("unused")
public static void main(String[] args) throws Throwable {
ApplicationContext ac =
new
ClassPathXmlApplicationContext("/com/targettrust/spring/remoting/server-
beans.xml");
while(true){
Thread.sleep(10000L);
}
}
}
Cdigo 5.23 ContextServer.java
Agora vamos a configurao xml do cliente, que poderia ser um programa Java
com RMI normal, nesse exemplo vamos utilizar os prprios recursos do Spring para
isso.
</beans>
XML 5.11 cliente-beans.xml
package com.targettrust.spring.remoting;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
HoraService hs = (HoraService)ac.getBean("horaService");
System.out.println("Hora vinda do Service: " + hs.getDate());
}
}
Cdigo 5.24 ContextCliente.java
Exerccios