Escolar Documentos
Profissional Documentos
Cultura Documentos
Apostila Spring
Apostila Spring
& '
*
+& ,-
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
Sobre o Autor
. /0
,&
7 89 4
9 0'
8,0: , ;
7
' ,
,'
' , ;
,
, (
"
5
6 98 6
, ; ;
1' 2
3
4 +5
6
0,
;, <0
)
;
Para cada novo uso ou distribuio, voc deve deixar claro para outros os termos da licena desta
obra.
Qualquer uma destas condies podem ser renunciadas, desde que Voc obtenha permisso do
autor.
Qualquer direito de uso legtimo (ou "fair use") concedido por lei, ou qualquer outro direito protegido
pela legislao local, no so em hiptese alguma afetados pelo disposto acima.
Este um sumrio para leigos da Licena Jurdica (na ntegra).
!!"#
"$"%$
& '#
#
(((
1. Introduo
Java a plataforma tecnolgica de maior sucesso na histria da computao. De uma simples linguagem
para a criao de pequenos aplicativos para set-top boxes (como as utilizada pela TV digital interativa), se
tornou uma plataforma completa, abrangendo desde programas para pequenos dispositivos at as maiores
aplicaes coorporativas do mundo.
A maioria das aplicaes desenvolvidas em Java hoje so focadas no mercado coorporativo. Estas
aplicaes geralmente possuem caractersticas bsicas em comum: interface web, persistncia em banco
de dados relacional, comunicao com outros sistemas, necessidade de autenticao e autorizao de
usurios, etc.
Para padronizar o desenvolvimento e os produtos disponveis, o consrcio que rege a plataforma Java, Java
Community Process (JCP), criou a macro-especificao Java 2 Enterprise Edition (J2EE). Esta rene
diversas especificaes menores que ditam sobre como as caractersticas de aplicaes coorporativas so
implementadas em Java, por exemplo como uma aplicao web em Java deve ser ou como acessar o
banco de dados nesta linguagem.
Como a plataforma Java utilizada universalmente, todo tipo de aplicao desenvolvida nela. J2EE foi
criada visando suportar aplicaes de grande porte e exerce muito bem seu papel neste cenrio, mas acaba
trazendo muita complexidade para o desenvolvimento de aplicaes no to grandes. Ocorre que a grande
maioria das aplicaes existentes hoje no de grande porte e no requer todos estes recursos, tendo
ainda assim que pagar o preo da complexidade de uma plataforma "Tamanho nico.
Para amenizar e reduzir este problema, surgiram alternativas vindas da comunidade de desenvolvedores
Java. Solues simples criadas por pequenos grupos se espalharam e tornaram-se um padro de facto.
Uma destas solues alternativas o Spring Framework, criado por Rod Johnson para amenizar os
problemas que este encontrava ao utilizar a tecnologia de Enterprise Java Beans (EJB), parte principal do
J2EE.
A prova da fora das solues alternativas veio com a verso 5.0 de J2EE, agora chamado apenas Java
Enterprise Edition (Java EE). Esta traz recursos que claramente foram inspirados tanto no Spring como em
outras solues alternativas. a padronizao de tcnicas e tecnologias que a comunidade de
desenvolvedores consagrou nos ltimos anos.
Esta apostila parte integrante de um curso sobre o Spring Framework, em sua verso 1.2. Seu contedo
visa explicar e treinar o leitor no uso desta ferramenta.
Apesar do lanamento da soluo padronizada trazida pelo Java EE 5.0, espera-se que a adoo desta
plataforma pelas empresas demore um bom tempo. Alm da necessidade de treinar todos os recursos
humanos nesta nova plataforma, existe a necessidade de atualizar os servidores de aplicao e mquinas
virtuais (Java EE 5.0 s funciona em Java Virtual Machines 5.0). Utilizando o Spring Framework e outras
solues alternativas, podemos ter os benefcios da nova verso do Java EE em servidores de aplicao e
JVMs antigas, a partir da verso 1.3 de Java.
!!"#
"$"%$
& '#
#
(((
Instanciao Direta
A forma mais natural de se obter uma referncia para o UsuarioDao
GerenciadorUsuarios seria instanciando-a diretamente, como no exemplo abaixo:
de
dentro
de
!!"#
"$"%$
& '#
#
(((
Uso de Registry
Existem diversas solues possveis para este problema, at a verso 1.4, J2EE utiliza a soluo de
registrar os recursos num diretrio de componentes chamado JNDI (Java Naming and Directory Interface).
Esta soluo baseada no Padro Arquitetural Registry. Ao utilizar o Registry, temos um lugar comum onde
as classes podem obter referncias a outras classes.
Registry um Padro Arquitetural onde componentes so obtidos atravs da consulta a um lugar comum.
Em J2EE geralmente utiliza-se a rvore JNDI.
No exemplo, poderamos fazer GerenciadorUsuarios obter uma referncia ao UsuarioDao por meio
do Registry JNDI. Primeiro, a classe UsuarioDao precisa ser registrada (o que chamado de bind),
geralmente isto feito pelo container utilizando arquivos de configurao (deployment descriptors) em um
cdigo parecido com este:
//configura o DAO
UsuarioDao usuarioDao = new UsuarioDao();
usuarioDao.setServidorBancoDeDados("mysql.fragmental.com.br:3306");
usuarioDao.setUsuario("pcalcado");
usuarioDao.setSenha("jap123");
usuarioDao.setSchema("curso-spring");
usuarioDao.setDriverJdbc("com.mysql.jdbc.Driver");
//... e mais configuraes
//Registra o DAO
Context ctx = new InitialContext();
ctx.bind("usuarioDao", usuarioDao);
Logo depois, a nossa classe pode obter uma referncia do Registry, processo chamado de lookup:
!!"#
"$"%$
& '#
#
(((
Dependency Injection
A pedra fundamental do Spring Framework o conceito de Dependency Injection.
Dependency Injection (Injeo de Dependncias - DI) uma forma de Inversion Of Control (Inverso de
Controle IoC) na qual um componente no instancia suas dependncias mas o ambiente (container)
automaticamente as fornece.
Este o Princpio de Hollywood: No me ligue, eu te ligo, ou seja: o objeto no chama o container, o
container chama o objeto. No exemplo, a classe GerenciadorUsuarios poderia ser implementada
exatamente desta forma:
!!"#
"$"%$
& '#
#
(((
Usos Indicados
Cada uma das formas de implementao de dependncias mostradas acima possui cenrios onde sua
aplicao tima.
Para componentes ou Services, o uso de instanciao direta altamente desaconselhvel. Componentes
geralmente so classes de granularidade grossa que fornecem servios a outros componentes e como visto
o uso de instanciao direta faria com que um componente criasse um acoplamento muito grande com
outro.
O uso de Registry para componentes til para lidar com o legado de aplicaes J2EE. Como veremos, o
Spring tambm pode trabalhar com JNDI o que facilita muito esta integrao. Alguns componentes de
infraestrutura tambm podem tirar proveito desta tcnica. De uma maneira geral, componentes de
aplicao, que no fazem parte da infraestrutura, tm maior benefcios quando implementadas utilizando
Dependency Injection.
Da mesma forma, o uso de Registry ou Dependency Injection para implementar a relao entre duas
classes simples um erro na maioria das vezes. Classes simples, principalmente se persistentes, devem
utilizar instanciao direta.
!!"#
"$"%$
& '#
#
(((
Exerccios
1 Dado o diagrama de classes abaixo, implemente a dependncia utilizando as trs formas descritas
neste captulo.
2 Dado o diagrama abaixo, identifique a melhor estratgia de implementao de cada uma das relaes
mostradas.
!!"#
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
O Arquivo ApplicationContext.xml
O applicationContext.xml onde so declarados os beans do Spring. O framework chama de beans
todas as classes que gerencia. As classes precisam ser declaradas utilizando o elemento <bean>, seguindo
o formato:
<bean id=identificador do bean class=FQN da classe que implementa o bean >
<property name=nome do atributo ref=id do bean que satisfaz a
dependncia />
</bean>
FQN significa Fully-Qualified Name, ou nome completo. O FQN de uma classe o nome da classe com o
seu pacote completo. Por exemplo, o FQN da classe String java.lang.String, o FQN da classe
List java.util.List.
No exemplo, declaramos os beans computadorBean, impressoraBean, monitorBean e tecladoBean.
O bean computadorBean possui como atributos referncias para os outros beans e estas referncias so
!!"#
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
}
public void presente() {
System.out.println(nome + " presente!");
}
}
Para criar e injetar a lista de alunos, podemos utilizar a sintaxe abaixo:
<bean id="sala"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.SalaDeAula">
<property name="alunos">
<list>
<ref bean="bernarda" />
<ref bean="phillip" />
<ref bean="valentina" />
</list>
</property>
</bean>
<bean id="bernarda"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.Aluno">
<property name="nome"><value>Bernarda</value></property>
</bean>
<bean id="phillip"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.Aluno">
<property name="nome"><value>Phillip</value></property>
</bean>
<bean id="valentina"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.Aluno">
<property name="nome"><value>Valentina</value></property>
</bean>
Simplesmente definimos um elemento <list> contendo os beans desejados na ordem desejada.
Caso o objeto receba um mapa (java.util.Map), tambm existe uma sintaxe facilitando sua
configurao:
public class Dicionario {
private Map definicoes = null;
public void setDefinicoes(Map definicoes) {
!!"#
"$"%$
& '#
#
(((
this.definicoes = definicoes;
}
public void imprimir() {
for (Iterator it = definicoes.keySet().iterator(); it.hasNext();) {
String palavra = (String) it.next();
System.out.println(palavra + " SIGNIFICA "
+ definicoes.get(palavra));
}
}
}
<bean id="dicionario"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.Dicionario">
<property name="definicoes">
<map>
<entry key="mother"><value>Me</value></entry>
<entry key="father"><value>Pai</value></entry>
</map>
</property>
</bean>
Existe ainda uma terceira facilidade, muito til quando utilizamos o Spring em conjunto com outros
frameworks, que a definio de Properties (java.util.Properties). Properties so o mecanismo
padro na plataforma Java para a criao de arquivos de configurao simples, o Spring permite que voc
crie esta configurao diretamente no applicationContext.xml, sem necessidade de arquivos
externos. Por exemplo, dada esta classe configurada via um arquivo Properties:
public class ConexaoBancoDeDados {
private String servidor = null;
private int porta = 0;
private String usuario = null;
private String senha = null;
public void setConfiguracao(Properties properties) {
this.servidor = properties.getProperty("banco.servidor");
this.porta =
Integer.parseInt(properties.getProperty("banco.porta"));
!!"#
"$"%$
& '#
#
(((
this.usuario = properties.getProperty("banco.usuario");
this.senha = properties.getProperty("banco.senha");
}
public void conectar() {
System.out.println("[" + usuario + "(" + senha + ")" + "@" +
servidor
+ ":" + porta + "]");
}
}
Podemos utilizar a seguinte sintaxe para a configurarmos via applicationContext.xml:
<bean id="conexao"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.ConexaoBancoDeDados">
<property name="configuracao">
<props>
<prop key="banco.servidor">fragmental.com.br</prop>
<prop key="banco.porta">3306</prop>
<prop key="banco.usuario">vmaia</prop>
<prop key="banco.senha">vc123al</prop>
</props>
</property>
</bean>
Em termos prticos, a diferena entre um mapa e um Properties que o ltimo s aceita Strings, enquanto
o anterior pode contm referncias a outros objetos. O uso de arquivos Properties, como mencionado,
muito til para a integrao com outros frameworks que sero vistos no decorrer do curso.
Nota: O uso do formato xyzBean para o id dos beans declarados (como em computadorBean ao invs
de simplesmente computador) no uma recomendao. Este formato foi utilizado apenas para deixar o
exemplo mais claro.
!!"#
"$"%$
& '#
#
(((
Exerccios
1 Crie arquivos de configurao do Spring para os cenrios descritos nos exerccios do captulo anterior.
2 Escreva classes correspondentes ao arquivo de configurao descrito abaixo:
<bean id="A"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.exerccios.ClasseA" />
<bean id="B"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.exerccios.ClasseB">
<property name="teste" ref="A" />
</bean>
<bean id="C"
class="br.com.fragmental.cursos.spring.apostila.capitulo3.exerccios.ClasseC">
<property name="lista"><list>
<ref bean="A" />
<ref bean="B" /></list>
</bean>
!!"#
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
}
//se passou nas checagens:
//emprstimo est aprovado
this.status=Status.APROVADO;
}
Para que este cdigo tire proveito dos recursos de aplicaes modernas, por exemplo para que possa
participar de transaes no banco de dados e criar registros em um arquivo de log, ele precisa ser
modificado para incluir cdigo que lida exclusivamente com isso, como abaixo.
public void aprovar() throws MaximoPrestacoesExcedidoException,
CreditoExcedidoException, SQLException, NamingException {
Connection conexao = criaTransacao();
// Checa se o emprstimo excede o limite do cliente
if (!cliente.podeEmprestar(this.valor)) {
logger.log(Level.INFO, "Emprstimo [" + this.getCodigo()
+ "] negado por exceder crdito em ["
+ this.getValor().subtrair(cliente.getCredito()) + "]");
this.status = Status.NEGADO;
throw new CreditoExcedidoException("Emprestimo muito alto");
}
// Checa se o numero de prestaes maior que o limite
if (prestacoes.size() > Prestacao.MAXIMO_PRESTACOES) {
logger.log(Level.INFO, "Emprstimo [" + this.getCodigo()
+ "] negado por exceder nmero mximo de prestaes ["
+ this.getPrestacoes().size() + "]");
this.status = Status.NEGADO;
throw new MaximoPrestacoesExcedidoException(
"O emprstimo deve ser pago em at "
+ Prestacao.MAXIMO_PRESTACOES + " vezes!");
}
// se passou nas checagens:
logger.log(Level.INFO, "Emprstimo [" + this.getCodigo()
!!"#
"$"%$
& '#
#
(((
+ "] aprovado");
// emprstimo est aprovado
this.status = Status.APROVADO;
conexao.commit();
}
A parte destacada em amarelo o cdigo adicionado exclusivamente para que o trecho de cdigo tenha
acesso aos recursos tecnolgicos. Como visto, o cdigo de negcios, que o que realmente importa ao
criar um software, fica soterrado no meio do cdigo de infra-estrutura, que existe apenas para satisfazer
necessidades tcnicas.
Mesmo neste exemplo extremamente simples o cdigo de infra-estrutura j representa boa parte do cdigo
da aplicao. Este problema faz com que mudanas em regras de negcio toquem o cdigo de infraestrutura, e vice-versa. No to fcil separar mudanas no aspecto no-funcional das funcionais, tudo
est no mesmo lugar!
Coeso a mtrica de quanto as linhas de cdigo em um mtodo (ou os mtodos em uma classe) so
relacionados entre si. Um mtodo que faz conexo com banco de dados e processa regras de negcio tem
baixa coeso.
Tambm existe o problema da repetio de cdigo. Mesmo lidando apenas com cdigo de negcios
podemos acabar tendo que repetir uma mesma rotina vrias vezes, linha por linha. No exemplo abaixo,
vemos que ao ser criado um novo Emprestimo um Funcionario precisa ser notificado do fato.
public Emprestimo solicitarEmprestimo() {
Emprestimo novo = new Emprestimo(this);
notificadorFuncionarios.notificar(novo);
return novo;
}
Acontece que por uma mudana nos requisitos agora o funcionrio deve ser avisado em qualquer alterao
no Status do Emprestimo, ento ao invs de fazer simplesmente this.status= o cdigo deve invocar
este mtodo:
private void setStatus(Status novoStatus) {
this.status = novoStatus;
notificadorFuncionarios.notificar(novoStatus);
}
Os dois mtodos, em classes diferentes, possuem rotinas para notificar o Funcionario. No se trata
apenas de encapsular esta rotina num mtodo, isso j foi feito (como o mtodo notificar()). O fato
deste mtodo ser invocado sempre e da mesma maneira por diversas classes que pode se tornar um
problema quando a implementao mudar. O ideal seria conseguir avisar ao sistema de que toda vez que
os mtodos solicitarEmprestimo() e setStatus() (e qualquer outro que precise desta
funcionalidade ) forem chamados deve ser disparada uma notificao.
!!"#
"$"%$
& '#
#
(((
Conceitos Ortogonais (Orthogonal Concerns) so os diversos conceitos com que um cdigo de aplicao
tem que lidar, como regras de negcio, segurana e conexes com bancos de dados.
A idia por trs de Aspect-Oriented Programming tratar estes conceitos em lugares separados (entendase classes separadas se estamos falando de Java) enquanto estamos desenvolvendo e uni-las em tempo
de execuo. Estes conceitos que se integram ao cdigo de negcios so chamados de Aspectos.
Aspectos so a separao do trecho de cdigo que implementa conceitos ortogonais em classes distintas
que so unidas em tempo de execuo (runtime).
Ao invs de um grande bloco de cdigo que cuida de transaes, segurana, conexo com o banco de
dados e ainda das regras de negcio ns podemos definir cada um destes aspectos em uma ou mais
classes diferentes e a ferramenta de AOP ir fazer esta mistura enquanto o programa executado. O
diagrama abaixo ilustra os diversos aspectos separados enquanto estamos desenvolvendo (esquerda) e o
produto final em tempo de execuo, a classe que mistura todos estes aspectos (direita).
Desenvolvimento
Execuo
Segurana
Segurana
Transaes
Transaes
Log
Log
Negcios
Negcios
Figura 4.2 Aspectos em Desenvolvimento e Execuo
Claro que desta forma podemos tambm reaproveitar os aspectos em diversas classes. Geralmente voc
vai precisar iniciar ou terminar transaes, verificar se o usurio tem os privilgios necessrios e demais
aspectos em diversas classes de negcio, utilizando AOP voc pode criar aspectos apenas uma vez e ligalos a diversas classes de negcio.
Aspectos so formados por:
Advices - Cdigo a ser executado para cumprir uma tarefa (abrir ou fechar uma conexo, por
exemplo)
Pointcuts Lugares na classe-alvo (a classe com regras de negcio) onde o Advice deve ser
invocado (por exemplo sempre que um mtodo da classe UsuarioDao for chamado)
Ou seja, podemos ter um aspecto descrito como: Toda vez que se invocar um mtodo cujo nome comece
com fechar (por exemplo fecharVenda) execute o cdigo que inicia uma transao no banco de dados.
Usos Indicados
AOP uma tcnica utilizada principalmente para duas coisas: prevenir repetio de cdigo e remover
cdigo de infra-estrutura do cdigo da aplicao. Ao contrrio do mito popular, no existe uma competio
entre AOP e OOP, uma complementa a outra. Tambm no h necessidade de utilizar OOP com tcnicas
!!"#
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
Exerccios
1 - O trecho de cdigo abaixo foi marcado em reas com conceitos ortogonais distintos. Identifique o
conceito implementado por cada rea.
public class Noticia {
private Usuario usuario = null;
private SecaoDoSite secao = null;
private String titulo=null;
private String texto = null;
public void publicar() throws UsuarioNaoAutorizadoException,
NamingException, SQLException {
// verifica se o usurio jornalista e se pode postar nesta seo
if (!(usuario.isJornalista() &&
usuario.temDireitoPublicacao(secao))) {
throw new UsuarioNaoAutorizadoException("No pode publicar");
}
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup("java:/comp/env");
DataSource ds = (DataSource) envContext.lookup("jdbc/mysql");
Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement("INSERT INTO MATERIAS
(titulo, texto) VALUES (?,?)");
ps.setString(0, titulo);
ps.setString(1, texto);
ps.execute();
conn.commit();
}
}
!!"#
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
class="br.com.fragmental.cursos.spring.apostila.capitulo5.PublicadorNotici
as">
<property name="gerenciadorArquivos" ref="gerenciadorArquivo"/>
</bean>
</beans>
Para testar, utilizamos este trecho de cdigo:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"classpath:br/com/fragmental/cursos/spring/apostila/capitulo3/applicationC
ontext-Capitulo3.xml");
Computador computador = (Computador)
applicationContext.getBean("computadorBean");
computador.ligar();
E temos como resultado impresso na sada do programa:
GerenciadorArquivos: SALVO [Lanado Spring Framework 2.0!] em
[/usr/local/reportagens]
Este o fluxo padro de negcios.
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
Nota: Para utilizar este exemplo voc precisa da biblioteca CGLIB2 no Classpath. Esta biblioteca permite
que o Spring mude o cdigo de classes e no trabalhe apenas com interfaces.
Existe tambm o After advice, que como o nome diz executado aps o mtodo. Por exemplo, vamos
definir um advice do tipo After que notifica (escrevendo na tela neste exemplo) sobre a publicao de uma
nova notcia. Este advice ser invocado aps o mtodo publicar() do PublicadorNoticias.
Primeiro, criamos o advice.
public class NotificacaoAdvice implements AfterReturningAdvice {
Notificador notificador = null;
public void afterReturning(Object valorDeRetorno, Method metodo,
Object[] argumentos, Object alvo) {
Arquivo arquivo = (Arquivo)argumentos[1];
notificador.notificarSobreNoticiaNova(arquivo.getNome());
}
public void setNotificador(Notificador notificador) {
this.notificador = notificador;
}
}
O mtodo afterReturning(), executado logo aps o mtodo na classe de negcios (nosso target)
apenas usa a informao recebida como parmetro e a envia ao notificador.
Para que este advice seja ativado, basta modificar o applicationContext.xml, acrescentando o advice
no ProxyFactory como fizemos com o advice Before anteriormente.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="gerenciadorArquivoTarget"
class="br.com.fragmental.cursos.spring.apostila.capitulo5.GerenciadorArqui
vos"/>
<bean id="gerenciadorArquivo"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property
name="interceptorNames"><list><value>notificacaoAdvice</value>
<value>logAdvice</value></list></property>
<property name="target" ref="gerenciadorArquivoTarget" />
</bean>
<bean id="logAdvice"
class="br.com.fragmental.cursos.spring.apostila.capitulo5.LogAdvice" />
!!"#
"$"%$
& '#
#
(((
<bean id="publicadorNoticias"
class="br.com.fragmental.cursos.spring.apostila.capitulo5.PublicadorNotici
as">
<property name="gerenciadorArquivos" ref="gerenciadorArquivo"/>
</bean>
<bean id="notificador"
class="br.com.fragmental.cursos.spring.apostila.capitulo5.Notificador" />
<bean id="notificacaoAdvice"
class="br.com.fragmental.cursos.spring.apostila.capitulo5.NotificacaoAdvice">
<property name="notificador" ref="notificador" />
</bean>
</beans>
Como pode ser percebido ns utilizamos um elemento <list> para definir dois valores, os nomes dos
advices. Podem haver mais de um advice de cada tipo sem problemas.
Outro ponto interessante que o advice em si um bean gerenciador pelo Spring e pode receber injeo
de dependncias: o notificacaoAdvice do exemplo injetado com um notificador.
A sada do cdigo de exemplo fica:
LOG --- Sat Aug 05 13:12:00 GMT-03:00 2006 --- Executdo mtodo 'salvarArquivo'
utilizando como parmetros
br.com.fragmental.cursos.spring.apostila.capitulo5.Diretorio@12a1e44
br.com.fragmental.cursos.spring.apostila.capitulo5.Arquivo@29428e
GerenciadorArquivos: SALVO [Lanado Spring Framework 2.0!] em
[/usr/local/reportagens]
Notificador: EXTRA EXTRA! 'Lanado Spring Framework 2.0!' !!!
Outro advice com comportamento muito parecido o Throws, que executado quando uma exceo
lanada. Para utilizar este advice deve-se implementar a interface ThrowsAdvice.
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
}
}
}
Para
termos
este
advice
applicationContext.xml:
funcionando
no
nosso
sistema
basta
configurarmos
"$"%$
& '#
#
(((
// conexo aberta...
System.out.println("Terceiro exemplo");
Conexao conexao2 = new Conexao();
conexao2.abrir();
dao.salvar(usuario, conexao2);
Temos a sada:
Primeiro exemplo
Conexo fechada, abrindo...
Invocando...
DAO: Executando SQL=[INSERT INTO USUARIOS VALUES(pcalcado)]
Fechando Conexo...
------------------------Segundo exemplo
Nenhuma conexo passada
------------------------Terceiro exemplo
Invocando...
DAO: Executando SQL=[INSERT INTO USUARIOS VALUES(pcalcado)]
Fechando Conexo...
!!"#
"$"%$
& '#
#
(((
Exerccios
1 Modifique o exemplo tirando o log da classe GerenciadorArquivos e colocando esta funcionalidade
na classe PublicadorNoticias.
2 Descubra quanto tempo os mtodos demoram para executar utilizando advices. Primeiro tente com
Before e After, depois com Around.
!!"#
"$"%$
& '#
#
(((
Entity Beans: Objetos que contm os dados sendo manipulados, com mapeamento direto do
banco de dados relacional
Para que sua aplicao disponha de recursos sofisticados de J2EE padro (sem uso de ferramentas de
terceiros) como controle de transaes indicado que sua modelagem siga esta diviso. Desta forma, se
descobrimos durante a anlise do sistema que devemos ter um objeto como o abaixo:
!!"#
"$"%$
& '#
#
(((
Ao utilizar EJBs, entretanto, teramos que mapear este objeto de negcio em pelo menos dois objetos:
Utilizando POJOs
A Figura 6.1 traz um exemplo claro de POJO. uma classe simples que representa um conceito de
negcio e no est presa nenhum framework ou biblioteca.
POJO (Plain Old Java Object) um objeto Java normal, que no implementa nem estende nenhuma classe
de infra-estrutura (de um framework, por exemplo). Um Servlet no um POJO porque precisa estender
javax.servlet.http.HttpServlet para funcionar.
Idealmente o desenvolvimento OO em Java deve ser feito utilizando POJOs. Os conceitos da aplicao
devem ser implementados de forma extremamente simples, sem influncia da arquitetura escolhida.
Como mencionado, esta abordagem possui problemas quando estamos utilizando J2EE. O maior deles
que a infra-estrutura provida por este framework no foi pensada para o uso de objetos simples e sim de
objetos integrados ao framework como EJBs e Servlets.
Para no deixar que a infra-estrutura J2EE influencie diretamente sua aplicao e ainda assim obter as
funcionalidades que J2EE traz para os sistemas preciso utilizar um chamado Container Leve.
Container Leve (Lightweight Container) um container que d a objetos Java normais (POJOs)
caractersticas que normalmente no estariam disponveis para estes, como mecanismos de segurana,
transaes e IoC.
Ao utilizar um container leve como o Spring possvel utilizarmos objetos simples como os da figura Figura
6.1 ao invs da estrutura artificial mostrada na Figura 6.2, exigida pelos EJBs.
Esta a caracterstica que distingue aplicaes baseadas em containeres leves (como Spring)de outras
baseadas em herana e frameworks intrusivos (como EJB).
!!"#
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
/>
<bean id="gerenciadorLivros"
class="br.com.fragmental.cursos.spring.apostila.capitulo6.GerenciadorLivro
s">
<property name="livroDao" ref="livroDaoOracle" />
</bean>
</beans>
Se quisermos que nosso sistema tambm possa
GerenciadorLivros como mostrado no diagrama abaixo.
utilizar
MySQL,
precisamos
alterar
!!"#
"$"%$
& '#
#
(((
<bean id="livroDaoMySQL"
class="br.com.fragmental.cursos.spring.apostila.capitulo6.LivroDaoMySQL"/>
<bean id="gerenciadorLivros"
class="br.com.fragmental.cursos.spring.apostila.capitulo6.GerenciadorLivro
s">
<property name="livroDao" ref="livroDaoMySQL" />
</bean>
</beans>
O simples fato de isolar a lgica de acesso a dados no DAO permite que o GerenciadorLivros possa ser
alterado sem muita alterao de cdigo, porm existe alterao no GerenciadorLivros e isso no
necessrio nem desejvel.
Num sistema de verdade estas mudanas simples deveriam ser feitas em diversos lugares para cada
mudana deste tipo, e este no o tipo de problema que ocorre apenas com mudanas drsticas como a
de o SGBD utilizado, ele se manifesta toda vez que alguma coisa na implementao mudar.
Pensando no problema, podemos abstrair o modelo chegando a concluso que o GerenciadorLivros
precisa de um DAO para persistir os objetos. O problema que motiva a mudana de cdigo no
GerenciadorLivros para mudarmos de banco de dados que da forma como est implementado hoje
este no depende de um DAO, ele depende do LivroDaoOracle especificamente (a nossa mudana
apenas o fez depender de outro DAO). Esta a dependncia a ser eliminada.
Para eliminarmos a dependncia direta, vamos fazer com que a classe GerenciadorLivros dependa de
fato de um DAO qualquer criando uma interface genrica para DAOs.
!!"#
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
this.gerenciadorAutores = gerenciadorAutores;
}
// metodos de negocio
}
Configurados no applicationContext.xml desta forma:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="gerenciadorAutores"
class="br.com.fragmental.cursos.spring.apostila.capitulo6.GerenciadorAutor
esImpl"/>
<bean id="gerenciadorEditoras"
class="br.com.fragmental.cursos.spring.apostila.capitulo6.GerenciadorEdito
rasImpl">
<property name="gerenciadorAutores" ref="gerenciadorAutores" />
</bean>
</beans>
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
!!"#
"$"%$
& '#
#
(((
"$"%$
& '#
#
(((
de um novo usurio:
public class GerenciadorUsuariosImpl implements GerenciadorUsuarios {
private GerenciadorFotos gerenciadorFotos = null;
private UsuarioRepository usuarioRepository=null;
public void setUsuarioRepository(UsuarioRepository usuarioRepository) {
this.usuarioRepository = usuarioRepository;
}
public Usuario novoUsuario(String login, File foto){
Usuario novoUsuario = new Usuario(login);
Foto fotoUsuario = gerenciadorFotos.enviarFoto(login, foto);
novoUsuario.setFoto(fotoUsuario);
usuarioRepository.salvar(novoUsuario);
return novoUsuario;
}
public void setGerenciadorFotos(GerenciadorFotos gerenciadorFotos) {
this.gerenciadorFotos = gerenciadorFotos;
}
}
!!"#
"$"%$
& '#
#
(((
Por ltimo, os Repositories so implementados por DAOs que, neste exemplo fictcio, apenas escrevem na
tela:
public class UsuarioDao implements UsuarioRepository{
public void salvar(Usuario usuario) {
System.out.println("SALVANDO USUARIO ["+usuario.getLogin()+"]");
}
}
!!"#
"$"%$
& '#
#
(((
Exerccios
1 No modelo apresentado na seo sobre Padres de Modelagem de Domnio, implemente a
funcionalidade que permite aos usurios:
a) Indicarem e removerem seus contatos
b) Enviarem e removerem fotos
c) Alterar sua foto de usurio
!!"#
"$"%$
& '#
#
(((
Bibliografia
6 & '$
, 0 ,$
& '#
#
)#
( >#
1'&'?
,A 0 ,
D; ,6D
6 & '$
& '#
#
6= !
, $E , F6= G$ +H
& ,$
I=""=%="%
6= !
)#
( >#
1'&'?
&,
,6
KH
&, 67
& '#
#
,
>6
) &67F
+'
,'
+'
' ,,6= %
+'
$ <
; #=DD ''
( >
#
,'
+H "%L %LG!"G
6= %
+H "LI=ILGI%G
( >
,#
"=1#
!!"#
"$"%$
1&
& '#
#
(((