Apostila Spring

download Apostila Spring

of 48

Transcript of Apostila Spring

  • 8/6/2019 Apostila Spring

    1/48

    !!"#"$"%$&'##((()

    Spring Framework

    &'*+&,-

    &'##((()

  • 8/6/2019 Apostila Spring

    2/48

    !!"#"$"%$&'##((()

    Sobre a Fragmental TI LTDA

    A Fragmental Tecnologia da Informao LTDA uma empresa prestadora de servios nas reas deconsultoria e treinamento em tecnologia. Sua especialidade o uso e divulgao de prticas consagradas emodernas para auxiliar o desenvolvimento de software.

    Esta apostila parte integrante dos treinamentos da Fragmental.

    Sobre o Autor

    ./0,(",1'23),&4+56789490'8,0:,;7569860,;,

  • 8/6/2019 Apostila Spring

    3/48

    !!"#"$"%$&'##((()

    1. IntroduoJava a plataforma tecnolgica de maior sucesso na histria da computao. De uma simples linguagempara 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 maioresaplicaes coorporativas do mundo.

    A maioria das aplicaes desenvolvidas em Java hoje so focadas no mercado coorporativo. Estasaplicaes geralmente possuem caractersticas bsicas em comum: interface web, persistncia em bancode dados relacional, comunicao com outros sistemas, necessidade de autenticao e autorizao deusurios, etc.

    Para padronizar o desenvolvimento e os produtos disponveis, o consrcio que rege a plataforma Java, JavaCommunity Process (JCP), criou a macro-especificao Java 2 Enterprise Edition (J2EE). Esta renediversas especificaes menores que ditam sobre como as caractersticas de aplicaes coorporativas soimplementadas em Java, por exemplo como uma aplicao web em Java deve ser ou como acessar obanco de dados nesta linguagem.

    Como a plataforma Java utilizada universalmente, todo tipo de aplicao desenvolvida nela. J2EE foicriada visando suportar aplicaes de grande porte e exerce muito bem seu papel neste cenrio, mas acabatrazendo muita complexidade para o desenvolvimento de aplicaes no to grandes. Ocorre que a grandemaioria das aplicaes existentes hoje no de grande porte e no requer todos estes recursos, tendoainda assim que pagar o preo da complexidade de uma plataforma "Tamanho nico.

    Para amenizar e reduzir este problema, surgiram alternativas vindas da comunidade de desenvolvedoresJava. 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 osproblemas que este encontrava ao utilizar a tecnologia de Enterprise Java Beans(EJB), parte principal doJ2EE.

    A prova da fora das solues alternativas veio com a verso 5.0 de J2EE, agora chamado apenas JavaEnterprise Edition(Java EE). Esta traz recursos que claramente foram inspirados tanto no Spring como emoutras solues alternativas. a padronizao de tcnicas e tecnologias que a comunidade dedesenvolvedores consagrou nos ltimos anos.

    Esta apostila parte integrante de um curso sobre o Spring Framework, em sua verso 1.2. Seu contedovisa 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 destaplataforma pelas empresas demore um bom tempo. Alm da necessidade de treinar todos os recursoshumanos nesta nova plataforma, existe a necessidade de atualizar os servidores de aplicao e mquinasvirtuais (Java EE 5.0 s funciona em Java Virtual Machines5.0). Utilizando o Spring Framework e outrassolues alternativas, podemos ter os benefcios da nova verso do Java EE em servidores de aplicao eJVMs antigas, a partir da verso 1.3 de Java.

  • 8/6/2019 Apostila Spring

    4/48

    !!"#"$"%$&'##((()

    2. Introduzindo Dependency InjectionAt mesmo o mais trivial dos sistemas em Java possui classes e componentes que se relacionam entre si.A forma como implementamos este relacionamento muito importante para a flexibilidade e qualidade geral

    do sistema.Imagine uma classe GerenciadorUsuarios , que para funcionar precisa ter acesso a uma classeUsuarioDao, que conecta ao banco de dados:

    Figura 2.1 Dependncia entre Classes do Exemplo

    publicclass GerenciadorUsuarios {

    private UsuarioDao usuarioDao=null;

    //... continuao da classe

    }

    Existem diversas maneiras de se implementar esta relao, vamos analisar algumas

    Instanciao Direta

    A forma mais natural de se obter uma referncia para o UsuarioDao de dentro deGerenciadorUsuarios seria instanciando-a diretamente, como no exemplo abaixo:

    publicclass GerenciadorUsuarios {

    private UsuarioDao usuarioDao= new UsuarioDao();

    //... continuao da classe

    }

    Instanciao Direta quando uma classe cria o objeto de que precisa. Em Java isso geralmente feito como operador new.

    Acontece que utilizando esta forma para componentes de aplicaes corporativas criada umadependncia muito grande entre os objetos. A classe GerenciadorUsuarios vai precisar saber comoiniciar a UsuarioDao para que esta possa operar. Vamos supor que a UsuarioDao necessite de algumaconfigurao para ser utilizada, esta configurao ter que ser feita no construtor da classeGerenciadorUsuarios :

    publicclass GerenciadorUsuarios {

    private UsuarioDao usuarioDao= null;

    public GerenciadorUsuario(){

    //configura o DAO

  • 8/6/2019 Apostila Spring

    5/48

    !!"#"$"%$&'##((()

    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

    }

    //... continuao da classe

    }

    Se qualquer uma destas configuraes mudar (mudar o nome do servidor, a porta de conexo, o driverutilizado, senha do banco de dados, etc.) esta classe ter que ser alterada. Estamos violando um princpiobsico de engenharia de software gerando um alto acoplamentoentre estas classes.

    Uso de Registry

    Existem diversas solues possveis para este problema, at a verso 1.4, J2EE utiliza a soluo deregistrar 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 ondeas 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 meiodo 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 umcdigo 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:

  • 8/6/2019 Apostila Spring

    6/48

    !!"#"$"%$&'##((()

    publicclass GerenciadorUsuarios {

    private UsuarioDao usuarioDao= null;

    public GerenciadorUsuarios(){

    try{

    Context ctx = new InitialContext();

    usuarioDao = (UsuarioDao) ctx.lookup("usuarioDao");

    }catch(NamingException ex){

    //tratar exceo

    }

    }

    //... continuao da classe

    }

    Desta forma a inicializao do componente fica fora da classe cliente deste, e geralmente pode ser feitaatravs de arquivos de configurao.

    Esta soluo por vezes implementada utilizando um objeto que segue o Design Pattern Singleton, fazendouso de mtodos estticos. Esta opo altamente problemtica porque o uso de Singletons e mtodosestticos tende a criar um sistema altamente procedural e com problemas diversos de concorrncia.

    Apesar de ser uma soluo muito boa para diversos casos, existem problemas nesta abordagem que

    tornam o desenvolvimento em Java EE mais complexo. O primeiro deles a dependncia gerada entre aclasse e o ambiente.

    No possvel utilizar a classe GerenciadorUsuarios fora de um ambiente onde JNDI esteja disponvel,e isto geralmente indica um Servidor de Aplicaes. Ao utilizar JNDI desta maneira ns perdemos aportabilidade da classe e seu reuso, j que no poderamos a reaproveitar em outros sistemas diferentes dooriginal (por exemplo um sistema feito em Java sem J2EE).

    Outro problema muito importante est na modelagem do sistema. Uma boa modelagem de negcios vaisempre representar o mundo real em objetos o mais prximo possvel da realidade e no mundo das regrasde negcio provavelmente no existe o conceito de bind ou lookup. Estes conceitos so complexidadeacidental, limitaes impostas pela plataforma.

    Finalmente, este tipo de alternativa consegue reunir boa parte dos problemas encontrados com o uso devariveis globais em toda a histria da Cincia da Computao.

    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 deControle 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, ocontainer chama o objeto. No exemplo, a classe GerenciadorUsuarios poderia ser implementadaexatamente desta forma:

  • 8/6/2019 Apostila Spring

    7/48

    !!"#"$"%$&'##((()

    publicclass GerenciadorUsuarios {

    private UsuarioDao usuarioDao= null;

    publicvoid setUsuarioDao(UsuarioDao usuarioDao) {

    this.usuarioDao = usuarioDao;

    }

    //... continuao da classe

    }

    E o container se encarregaria de instanciar o UsuarioDao e chamar o mtodo setUsuarioDao() , comono trecho de cdigo abaixo:

    // 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

    //coloca o usuarioDao dentro do GerenciadorUsuarios

    gerenciadorUsuarios.setUsuarioDao(usuarioDao);

    No caso do Spring, preciso declarar as dependncias em um arquivo de configurao. Toda a parte deinstanciar o objeto e injetar esta instncia feito de maneira automtica.

    Ao utilizar DI, a classe no depende mais do ambiente. Se utilizado fora de um container, basta que algumo fornea suas dependncias utilizando um trecho de cdigo como o descrito acima. Tambm no precisasaber anda sobre a infraestrutura, se usa JNDI ou outro recurso, j que no precisa invoca-la.

    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. Componentesgeralmente so classes de granularidade grossa que fornecem servios a outros componentes e como vistoo uso de instanciao direta faria com que um componente criasse um acoplamento muito grande comoutro.

    O uso de Registry para componentes til para lidar com o legado de aplicaes J2EE. Como veremos, oSpring tambm pode trabalhar com JNDI o que facilita muito esta integrao. Alguns componentes deinfraestrutura tambm podem tirar proveito desta tcnica. De uma maneira geral, componentes deaplicao, que no fazem parte da infraestrutura, tm maior benefcios quando implementadas utilizandoDependency 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, devemutilizar instanciao direta.

  • 8/6/2019 Apostila Spring

    8/48

    !!"#"$"%$&'##((()

    Exerccios

    1 Dado o diagrama de classes abaixo, implemente a dependncia utilizando as trs formas descritasneste captulo.

    2 Dado o diagrama abaixo, identifique a melhor estratgia de implementao de cada uma das relaesmostradas.

  • 8/6/2019 Apostila Spring

    9/48

    !!"#"$"%$&'##((()

    3. Dependency Injection no Spring FrameworkUm bom entendimento do conceito de DI fundamental para o bom uso do Spring. Toda a plataforma destaferramenta baseada neste conceito.

    Implementar DI no Spring muito simples.Vamos a um exemplo ilustrativo:

    Figura 3.1 Domnio do Exemplo

    Temos uma classe Computador que possui referncias para diversas outras classes que compem osistema. Vamos utilizar o Spring para automaticamente instanciar estas dependncias do Computador e osinjetar no objeto. Primeiro, definimos as classes envolvidas:

    publicclass Computador {

    private Impressora impressora = null;

    privateMonitormonitor = null;

    private Teclado teclado = null;

    publicvoid setImpressora(Impressora impressora) {

    this.impressora = impressora;

    }

    publicvoid setMonitor(Monitor monitor) {

    this.monitor = monitor;

    }

    publicvoid setTeclado(Teclado teclado) {

    this.teclado = teclado;

    }

    publicvoid ligar(){

    monitor.exibeMensagem("Digite texto para impresso");

  • 8/6/2019 Apostila Spring

    10/48

    !!"#"$"%$&'##((()

    String texto = teclado.ler();

    impressora.imprimir(texto);

    monitor.exibeMensagem("Texto Impresso!");

    }

    }

    publicclass Impressora {

    publicvoid imprimir(String texto) {

    // nossa impressora virtual apenasescreve na tela

    System.out.println("[IMPRESSORA] " + texto);

    }

    }

    publicclass Monitor {

    /**

    *Exibeumamensagemdetexto.

    *

    *@parammensagem

    */

    publicvoid exibeMensagem(String mensagem) {

    // No nosso exemplo, vamos exibir a mensagem na sada principal

    System.out.println("[MONITOR] "+mensagem);

    }

    }

    publicclass Teclado {

    /**

    *Lumtesxtodousurio.

    *

    *@return

    */

    public String ler() {

  • 8/6/2019 Apostila Spring

    11/48

    !!"#"$"%$&'##((()

    String texto = null;

    //imprime um 'prompt'

    System.out.print("[TECLADO]>");

    try {

    texto = new BufferedReader(new InputStreamReader(System.in))

    .readLine();

    } catch (IOException e) {

    System.out.println("Erro lendo teclado!");

    e.printStackTrace();

    }

    return texto;

    }

    }

    Note que no existe cdigo de inicializao das outras classes na classe Computador. Se instanciarmosesta classe manualmente e executarmos o mtodo ligar() teremos uma NullPointerException jque os componentes que ele necessita no foram fornecidos.

    Para testarmos nossa implementao, podemos criar uma classe que inicializa e supre todas asdependncias, como a descrita abaixo:

    publicclass IniciaComputador {

    publicstaticvoid main(String[] args) {

    Computador computador = new Computador();

    computador.setImpressora(new Impressora());

    computador.setTeclado(new Teclado());

    computador.setMonitor(new Monitor());

    computador.ligar();

    }

    }

    Esta classe til para testes unitrios (um conceito que veremos adiante), mas para o uso na aplicao realvamos deixar este trabalho para o Spring.

    Para fazer o Spring entender a dependncia entre nossas classes, precisamos criar um arquivo deconfigurao. Este geralmente recebe o nome de applicationContext.xml . Vejamos o arquivo quedefine nosso exemplo:

  • 8/6/2019 Apostila Spring

    12/48

    !!"#"$"%$&'##((()

    E para testar nosso exemplo utilizando Spring podemos utilizar a classe abaixo:

    publicclass IniciaUsandoSpring {

    publicstaticvoid main(String[] args) {

    ApplicationContext applicationContext = new

    ClassPathXmlApplicationContext(

    "classpath:br/com/fragmental/cursos/spring/apostila/capitulo3/applicationC

    ontext-Capitulo3.xml");

    Computador computador = (Computador)applicationContext.getBean("computadorBean");

    computador.ligar();

    }

    }

    Para entender o que o Spring requer como configurao, vamos analisar o arquivo de configurao.

    O Arquivo ApplicationContext.xml

    O applicationContext.xml onde so declarados os beansdo Spring. O framework chama de beans

    todas as classes que gerencia. As classes precisam ser declaradas utilizando o elemento , seguindoo formato:

    FQNsignifica Fully-Qualified Name, ou nome completo. O FQN de uma classe o nome da classe com oseu 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

  • 8/6/2019 Apostila Spring

    13/48

    !!"#"$"%$&'##((()

    declaradas utilizando elementos property dentro da declarao do bean.

    Ao utilizar o elemento property, o Spring ir tentar utilizar um mtodo setNomeDoAtributo() parapreencher o bean com a dependncia configurada.

    Muitas vezes, para no quebrar a invariante (veja [ContratosNulos]) de um objeto necessrio que suasdependncias sejam supridas durante a inicializao deste. Para estes casos, o Spring oferece apossibilidade de injetar as dependncias utilizando o construtor do objeto ao invs de seus mtodosmutadores (setters).

    Imagine que tenhamos um objeto Carro que para funcionar sempre precisa de um objeto Motor. Como apresena de um Motor faz parte da invariante do Carro, ele recebido no construtor:

    publicclass Carro {

    private Motor motor = null;

    public Carro(Motor motor) {

    super();

    this.motor = motor;

    }

    publicvoid rodar() {

    motor.iniciar();

    }

    }

    publicclass Motor {

    publicvoid iniciar() {

    System.out.println("Motor iniciado");

    }

    }

    Para definir a mensagem, utilizamos o arquivo de configurao abaixo:

    Literais, Listas e Mapas

    As dependncias podem ser outros beans ou valores. Quando a dependncia de um bean, o atributo refdo elemento property deve ser utilizado para indicar o bean desejado, como no nosso exemplo.

    Podemos tambm definir valores simples (texto ou numerais) diretamente no XML, como no exemploabaixo:

  • 8/6/2019 Apostila Spring

    14/48

    !!"#"$"%$&'##((()

    publicclass AloMundo {

    private String mensagem=null;

    publicvoid setMensagem(String mensagem) {

    this.mensagem = mensagem;

    }

    publicvoid executar(){

    System.out.println("Mensagem: "+mensagem);

    }

    }

    Podemos definir o contedo do atributo mensagem diretamente no applicationContext.xml , comoabaixo:

    Testando

    O arquivo de configurao tambm possui suporte para listas de elementos. Suponha, por exemplo, quetemos uma classe como a descrita abaixo.

    publicclass SalaDeAula {

    private List alunos = null;

    publicvoid setAlunos(List alunos) {

    this.alunos = alunos;

    }

    publicvoid chamada(){

    for (Iterator it = alunos.iterator(); it.hasNext();) {

    Aluno aluno = (Aluno) it.next();

    aluno.presente();

    }

    }

    }

    Que recebe uma lista de Alunos como argumento em seu construtor. A classe Aluno bem simples:

    publicclass Aluno {

    private String nome = null;

    publicvoid setNome(String nome) {

    this.nome = nome;

  • 8/6/2019 Apostila Spring

    15/48

    !!"#"$"%$&'##((()

    }

    public void presente() {

    System.out.println(nome + " presente!");

    }

    }

    Para criar e injetar a lista de alunos, podemos utilizar a sintaxe abaixo:

    Bernarda

    Phillip

    Valentina

    Simplesmente definimos um elemento contendo os beans desejados na ordem desejada.

    Caso o objeto receba um mapa (java.util.Map), tambm existe uma sintaxe facilitando suaconfigurao:

    publicclass Dicionario {

    private Map definicoes = null;

    publicvoid setDefinicoes(Map definicoes) {

  • 8/6/2019 Apostila Spring

    16/48

    !!"#"$"%$&'##((()

    this.definicoes = definicoes;

    }

    publicvoid imprimir() {

    for (Iterator it = definicoes.keySet().iterator(); it.hasNext();) {

    String palavra = (String) it.next();

    System.out.println(palavra + " SIGNIFICA "

    + definicoes.get(palavra));

    }

    }

    }

    Me

    Pai

    Existe ainda uma terceira facilidade, muito til quando utilizamos o Spring em conjunto com outrosframeworks, que a definio de Properties (java.util.Properties ). Properties so o mecanismopadro na plataforma Java para a criao de arquivos de configurao simples, o Spring permite que voccrie esta configurao diretamente no applicationContext.xml , sem necessidade de arquivosexternos. Por exemplo, dada esta classe configurada via um arquivo Properties:

    publicclass ConexaoBancoDeDados {

    private String servidor = null;

    privateintporta = 0;

    private String usuario = null;

    private String senha = null;

    publicvoid setConfiguracao(Properties properties) {

    this.servidor = properties.getProperty("banco.servidor");

    this.porta =

    Integer.parseInt(properties.getProperty("banco.porta"));

  • 8/6/2019 Apostila Spring

    17/48

    !!"#"$"%$&'##((()

    this.usuario = properties.getProperty("banco.usuario");

    this.senha = properties.getProperty("banco.senha");

    }

    publicvoid conectar() {

    System.out.println("[" + usuario + "(" + senha + ")" + "@" +

    servidor

    + ":" + porta + "]");

    }

    }

    Podemos utilizar a seguinte sintaxe para a configurarmos via applicationContext.xml :

    fragmental.com.br

    3306

    vmaia

    vc123al

    Em termos prticos, a diferena entre um mapa e um Properties que o ltimo s aceita Strings, enquantoo 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 oexemplo mais claro.

  • 8/6/2019 Apostila Spring

    18/48

    !!"#"$"%$&'##((()

    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:

  • 8/6/2019 Apostila Spring

    19/48

    !!"#"$"%$&'##((()

    4. Introduzindo Aspect-Oriented ProgrammingA programao Orientada a Objetos (Object-Oriented Programming - OOP) utilizada para dar maismodularidade ao cdigo desenvolvido e para deixar o software mais parecido com o mundo real. Ao utilizar

    corretamente objetos, podemos mapear quase que diretamente os problemas do mundo real para software.Por exemplo, ao modelarmos um sistema que cuida da aprovao de emprstimos, podemos trazer osconceitos envolvido (emprstimo, crdito, cliente...) diretamente para nosso software, como no diagramaabaixo.

    Figura 4.1 Domnio de um Sistema

    Entretanto, ainda existem e existiro por muito tempo limitaes tcnicas que fazem com que os conceitosde negcio que modelamos sofram invaso de conceitos tcnicos, como autenticao de usurios,transaes com bancos de dados e arquivos de log. Estes conceitos no fazem parte do domnio doproblema, existem apenas para satisfazer a necessidade do software.

    Normalmente, o que se faz com OOP simplesmente misturar estes conceitos, criando cdigo que misturaregras de negcio com limitaes tecnolgicas. Por exemplo, o mtodo abaixo traz o cdigo de negciosnecessrio para aprovar um emprstimo no exemplo acima.

    publicvoid aprovar() throws MaximoPrestacoesExcedidoException,

    CreditoExcedidoException{

    //Checa se o emprstimo excede o limite do cliente

    if(!cliente.podeEmprestar(this.valor)){

    this.status=Status.NEGADO;

    thrownew CreditoExcedidoException("Emprestimo muito alto");

    }

    //Checa se o numero de prestaes maior que o limite

    if(prestacoes.size()>Prestacao.MAXIMO_PRESTACOES){

    this.status=Status.NEGADO;

    thrownew MaximoPrestacoesExcedidoException( "O emprstimo deve serpago em at "+Prestacao.MAXIMO_PRESTACOES+" vezes!");

  • 8/6/2019 Apostila Spring

    20/48

    !!"#"$"%$&'##((()

    }

    //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 possaparticipar de transaes no banco de dados e criar registros em um arquivo de log, ele precisa sermodificado para incluir cdigo que lida exclusivamente com isso, como abaixo.

    publicvoid 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;

    thrownew 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;

    thrownew MaximoPrestacoesExcedidoException(

    "O emprstimo deve ser pago em at "

    + Prestacao.MAXIMO_PRESTACOES + " vezes!");

    }

    // se passou nas checagens:

    logger.log(Level.INFO, "Emprstimo [" + this.getCodigo()

  • 8/6/2019 Apostila Spring

    21/48

    !!"#"$"%$&'##((()

    + "] 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 tenhaacesso aos recursos tecnolgicos. Como visto, o cdigo de negcios, que o que realmente importa aocriar um software, fica soterrado no meio do cdigo de infra-estrutura, que existe apenas para satisfazernecessidades tcnicas.

    Mesmo neste exemplo extremamente simples o cdigo de infra-estrutura j representa boa parte do cdigoda aplicao. Este problema faz com que mudanas em regras de negcio toquem o cdigo de infra-estrutura, 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) sorelacionados entre si. Um mtodo que faz conexo com banco de dados e processa regras de negcio tembaixa coeso.

    Tambm existe o problema da repetio de cdigo. Mesmo lidando apenas com cdigo de negciospodemos 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 alteraono Status do Emprestimo, ento ao invs de fazer simplesmente this.status= o cdigo deve invocareste mtodo:

    privatevoid setStatus(Status novoStatus) {

    this.status = novoStatus;

    notificadorFuncionarios.notificar(novoStatus);

    }

    Os dois mtodos, em classes diferentes, possuem rotinas para notificar o Funcionario. No se trataapenas de encapsular esta rotina num mtodo, isso j foi feito (como o mtodo notificar()). O fatodeste mtodo ser invocado sempre e da mesma maneira por diversas classes que pode se tornar umproblema quando a implementao mudar. O ideal seria conseguir avisar ao sistema de que toda vez queos mtodos solicitarEmprestimo() e setStatus() (e qualquer outro que precise destafuncionalidade ) forem chamados deve ser disparada uma notificao.

    Conceitos Ortogonais e Aspectos

    Como visto, temos uma mistura de cdigo que lida com vrios interesses distintos ao escrever cdigo. Estes

    interesses so chamados de conceitos ortogonais.

  • 8/6/2019 Apostila Spring

    22/48

    !!"#"$"%$&'##((()

    Conceitos Ortogonais(Orthogonal Concerns) so os diversos conceitos com que um cdigo de aplicaotem 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 (entenda-

    se classes separadas se estamos falando de Java) enquanto estamos desenvolvendo e uni-las em tempode execuo. Estes conceitos que se integram ao cdigo de negcios so chamados de Aspectos.

    Aspectosso a separao do trecho de cdigo que implementa conceitos ortogonais em classes distintasque so unidas em tempo de execuo (runtime).

    Ao invs de um grande bloco de cdigo que cuida de transaes, segurana, conexo com o banco dedados e ainda das regras de negcio ns podemos definir cada um destes aspectos em uma ou maisclasses diferentes e a ferramenta de AOP ir fazer esta mistura enquanto o programa executado. Odiagrama abaixo ilustra os diversos aspectos separados enquanto estamos desenvolvendo (esquerda) e oproduto final em tempo de execuo, a classe que mistura todos estes aspectos (direita).

    Segurana

    Transaes

    Log

    Negcios

    Segurana

    Transaes

    Log

    Negcios

    Desenvolvimento Execuo

    Figura 4.2 Aspectos em Desenvolvimento e Execuo

    Claro que desta forma podemos tambm reaproveitar os aspectos em diversas classes. Geralmente vocvai precisar iniciar ou terminar transaes, verificar se o usurio tem os privilgios necessrios e demaisaspectos em diversas classes de negcio, utilizando AOP voc pode criar aspectos apenas uma vez e liga-los 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 serinvocado (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 comececom 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 competioentre AOP e OOP, uma complementa a outra. Tambm no h necessidade de utilizar OOP com tcnicas

  • 8/6/2019 Apostila Spring

    23/48

    !!"#"$"%$&'##((()

    de AOP, teoricamente podemos ter os mesmos benefcios em outros paradigmas.

    Containeres como o Spring e EJB 3.0 utilizam AOP para atuar de forma transparente. Alm deinterceptarem o fluxo de execuo do cdigo para controlar a forma com que as classes se comportam, elesoferecem recursos para que o programador defina seus prprios aspectos.

    importante notar que AOP uma tcnica til para fazer o que foi pensada: separar conceitos misturadosem um nico artefato de cdigo (como uma classe) em outros, reutilizveis. A tecnologia em si poderosa epossibilita usos muito mais amplos mas normalmente isso no uma boa idia, causando complexidadeexcessiva que no se faz necessria.

  • 8/6/2019 Apostila Spring

    24/48

    !!"#"$"%$&'##((()

    Exerccios

    1 - O trecho de cdigo abaixo foi marcado em reas com conceitos ortogonais distintos. Identifique oconceito implementado por cada rea.

    public class Noticia {

    private Usuario usuario = null;

    private SecaoDoSite secao = null;

    private String titulo=null;

    private String texto = null;

    publicvoid publicar() throws UsuarioNaoAutorizadoException,NamingException, SQLException {

    // verifica se o usurio jornalista e se pode postar nesta seo

    if (!(usuario.isJornalista() &&usuario.temDireitoPublicacao(secao))) {

    thrownew 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();

    }

    }

  • 8/6/2019 Apostila Spring

    25/48

    !!"#"$"%$&'##((()

    5. Aspect-Oriented Programming no Spring FrameworkO Spring utiliza AOP para implementar o controle que realiza sobre seus beans, por exemplo ao gerenciartransaes configuradas no applicationContext.xml . A estrutura de AOP provida pelo framework no

    oferece todos os recursos de outras implementaes mas os recursos oferecidos costumam ser mais quesuficientes para a criao de aplicativos.

    Nota: A Interface21, empresa que emprega a maioria dos desenvolvedores do Spring Framework, contratouh algum tempo o criado do AspectJ, framework Java mais famoso e poderoso para AOP. A integraoentre estes frameworks j pode ser vista na verso 2.0 do Spring Framework, trazendo a maioria dosrecursos de AOP no presentes em verses anteriores.

    Para entender como podemos implementar AOP no Spring vamos a um exemplo simples. Existe umaclasse responsvel por salvar arquivos no disco rgido (como um exemplo a parte que efetivamenteescreveria o arquivo em disco no est presente).

    publicclass GerenciadorArquivos {

    publicvoid salvarArquivo(Diretorio diretorioASalvar, Arquivo

    arquivoSalvo){

    System.out.println("GerenciadorArquivos: SALVO

    ["+arquivoSalvo.getNome()+"] em ["+diretorioASalvar.getNome()+"]");

    }

    }

    Esta classe utilizada por outra responsvel por publicar notcias, cada notcia viraria um arquivo.

    publicclass PublicadorNoticias {

    private GerenciadorArquivos gerenciadorArquivos = null;

    publicvoid setGerenciadorArquivos(GerenciadorArquivos

    gerenciadorArquivos) {

    this.gerenciadorArquivos = gerenciadorArquivos;

    }

    publicvoid publicar(String titulo){

    Arquivo arquivo = new Arquivo(titulo);

    Diretorio diretorio = new Diretorio("/usr/local/reportagens");

    gerenciadorArquivos.salvarArquivo(diretorio, arquivo);

    }

    }

    Isso tudo configurado no Spring como vimos em captulos anteriores:

  • 8/6/2019 Apostila Spring

    26/48

    !!"#"$"%$&'##((()

    class="br.com.fragmental.cursos.spring.apostila.capitulo5.PublicadorNotici

    as">

    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.

    Utilizando Advices Before e After

    Para evitar a escrita de arquivos desnecessrios em disco, foi determinado que uma mensagem deve serimprimida num arquivo de log sempre que um arquivo for salvo. O meio mais simples seria fazer a classeGerenciadorArquivos escrever este log, mas j vimos que misturar cdigo de negcios com cdigo deinfra-estrutura problemtico. Podemos ento utilizar AOP para criar um aspecto que faa o log.

    O primeiro passo criar o advice. No caso usaremos um advice do tipo Before, chamado antes dainvocao real do mtodo.

    publicclass LogAdvice implements MethodBeforeAdvice {

    publicvoid before(Method metodo, Object[] argumentos, Object alvo) {

    // lista de parmetros

    StringBuffer lista = new StringBuffer();

    for (int i = 0; i < argumentos.length; i++) {

    lista.append("\n" + argumentos[i]);

    }

    System.out.println("LOG --- " + new Date() + " --- Executado mtodo

    '"

    + metodo.getName() + "' utilizando como parmetros " +

    lista);

    }

    }

    Depois, modificamos o applicationContext.xml . Note que alteramos o id do GerenciadorArquivospara gerenciadorArquivosTarget. Esta mudana se faz necessria porque agora ogerenciadorArquivos no mais apenas uma instncia da nossa classe GerenciadorArquivos, o que o

    PublicadorNoticias recebe uma mistura entre a classe GerenciadorArquivos e o LogAdvice,criada em tempo de execuo pelo Spring.

  • 8/6/2019 Apostila Spring

    27/48

    !!"#"$"%$&'##((()

    logAdvice

    Esta mistura feita quando ns declaramos que o bean gerenciadorArquivos agora uma instncia deProxyFactoryBean . Esta classe fornecida pelo Spring Framework configurada com o target quedefinimos antes e a lista de advices que devem ser aplicados.

    Target a classe crua que vai ser misturada com os advices para gerar uma classe modificada.

    A sada aps estas modificaes :

    LOG --- Sat Aug 05 21:29:25 GMT-03:00 2006 --- Executado mtodo 'salvarArquivo'

    utilizando como parmetros

    br.com.fragmental.cursos.spring.apostila.capitulo5.Diretorio@ed0338

    br.com.fragmental.cursos.spring.apostila.capitulo5.Arquivo@6e70c7

    GerenciadorArquivos: SALVO [Lanado Spring Framework 2.0!] em

    [/usr/local/reportagens]

    Ou seja: adicionamos a funcionalidade de registrar a execuo do mtodo sem alterar qualquer linha de

    cdigo da classe GerenciadorArquivos .

  • 8/6/2019 Apostila Spring

    28/48

    !!"#"$"%$&'##((()

    Nota: Para utilizar este exemplo voc precisa da biblioteca CGLIB2 no Classpath. Esta biblioteca permiteque 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 umanova notcia. Este advice ser invocado aps o mtodo publicar() do PublicadorNoticias .

    Primeiro, criamos o advice.

    publicclass NotificacaoAdvice implements AfterReturningAdvice {

    Notificador notificador = null;

    publicvoid afterReturning(Object valorDeRetorno, Method metodo,

    Object[] argumentos, Object alvo) {

    Arquivo arquivo = (Arquivo)argumentos[1];

    notificador.notificarSobreNoticiaNova(arquivo.getNome());

    }

    publicvoid 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.

    notificacaoAdvice

    logAdvice

  • 8/6/2019 Apostila Spring

    29/48

    !!"#"$"%$&'##((()

    Como pode ser percebido ns utilizamos um elemento para definir dois valores, os nomes dosadvices. 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 injeode dependncias: o notificacaoAdvicedo 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.

    Advice do Tipo Around

    Advices Before e After j so muito poderosos em si, mas eles possuem grandes limitaes: advices Afterno podem alterar o retorno e a nica maneira de um advice Before no permitir a execuo do mtodo dotarget, por exemplo porque quebra uma restrio de segurana, lanando uma exceo.

    Para operaes que realmente interfiram na execuo de um mtodo devemos utilizar o Around advice.Este advice muito utilizado nos mecanismos internos do Spring, para demonstrar seu uso vamos a outroexemplo.

    Temos uma classe UsuarioDao que recebe uma conexo, um objeto usurio e o salva no banco de dados(este cdigo meramente ilustrativo e no deve ser tomado como exemplo de DAO).

    publicclass UsuarioDao {

    publicvoid salvar(Usuario usuario, Conexao conexao) {

  • 8/6/2019 Apostila Spring

    30/48

    !!"#"$"%$&'##((()

    String sql = "INSERT INTO USUARIOS VALUES(" + usuario.getLogin() +

    ")";

    System.out.println("DAO: Executando SQL=[" + sql + "]");

    conexao.executar(sql);

    }

    }

    Acontece que aps algum tempo percebeu-se que no h como garantir que a conexo esteja abertaquando o DAO a receber. Ao invs de modificar todos os DAOs do sistema mais simples criar um adviceque cuide deste processo de abertura e fechamento de conexo. Abaixo temos um advice tipo Around quecumpre este papel.

    publicclass VerificaConexaoDisponivelAdvice implements MethodInterceptor {

    public Object invoke(MethodInvocation invocacao) {

    Object[] argumentos = invocacao.getArguments();

    // pega a conexo passada como parmetro

    Conexao conexao = (Conexao) argumentos[1];

    // se no existe conexo, retorne

    if (conexao == null) {

    System.out.println("Nenhuma conexo passada");

    returnnull;

    } else {

    // se a conexo existe mas no est aberta, abra-a

    if (!conexao.isAberta()) {System.out.println("Conexo fechada, abrindo...");

    conexao.abrir();

    }

    // execute o mtodo

    try {

    System.out.println("Invocando...");

    invocacao.proceed();

    } catch (Throwable e) {

    // problemas na execuo do mtodo!

    e.printStackTrace();

    }

    finally{

    //Fechando conexo usada

    System.out.println("Fechando Conexo...");

    conexao.fechar();

    }

    // este mtodo no tem retorno (void)

    returnnull;

  • 8/6/2019 Apostila Spring

    31/48

  • 8/6/2019 Apostila Spring

    32/48

    !!"#"$"%$&'##((()

    // 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...

  • 8/6/2019 Apostila Spring

    33/48

    !!"#"$"%$&'##((()

    Exerccios

    1 Modifique o exemplo tirando o log da classe GerenciadorArquivos e colocando esta funcionalidadena classe PublicadorNoticias .

    2 Descubra quanto tempo os mtodos demoram para executar utilizando advices. Primeiro tente comBefore e After, depois com Around.

  • 8/6/2019 Apostila Spring

    34/48

    !!"#"$"%$&'##((()

    6. Aplicaes Baseadas em POJOsComo vimos, o uso do Spring Framework tem como grande vantagem o fato de no interferir diretamente namodelagem da sua aplicao. O uso de um container de IoC como o Spring afeta a arquitetura do sistema

    (como quando se escolhe IoC ao invs do uso de Registry, ou POJOsao invs de EJBs) mas os objetos denegcio no sofrem muitos impactos.

    Como Arquiteturaentendemos o conjunto de decises sobre a diviso de um sistema em mdulos e aforma como estes mdulos interagem.

    Mais que isso, o Spring induz ao uso de boas prticas de programao ao se basear ostensivamente eminterfaces ao invs de classes. Esta caracterstica, alm de permitir extenso e adaptao fcil doframework e ser um conceito da Orientao a Objetos, possibilita o uso de testes unitrios com muitafacilidade.

    Projetando Aplicaes J2EE

    A cultura de desenvolvimento J2EE difundida por livros e fornecedores at pouco tempo (e que continuaenraizada na maioria dos ambientes de desenvolvimento) de que se deve ter dois tipos de objetos numsistema: objetos de dados e objetos de lgica.

    A prtica de separar objetos nestes dois seguimentos completamente avessa aos objetivos originais daOrientao a Objetos, que de ter estado (dados) e comportamento (lgica) no mesmo componente (veja).

    O framework EJB divide seus componentes em trs tipos bsicos:

    Message-Driven Beans: Classes que consomem mensagens assncronas via JMS

    Session Beans: Objetos que implementam a lgica de negcios a ser executada

    Entity Beans: Objetos que contm os dados sendo manipulados, com mapeamento direto dobanco de dados relacional

    Para que sua aplicao disponha de recursos sofisticados de J2EE padro (sem uso de ferramentas deterceiros) como controle de transaes indicado que sua modelagem siga esta diviso. Desta forma, sedescobrimos durante a anlise do sistema que devemos ter um objeto como o abaixo:

    Figura 6.1 Objeto Encontrado na Anlise

    Este objeto rene estado e comportamento relativos ao conceito que queremos modelar em software, nocaso uma msica. Ele mapeia da melhor maneira possvel o conceito que entendemos como msica paraobjetos.

  • 8/6/2019 Apostila Spring

    35/48

    !!"#"$"%$&'##((()

    Ao utilizar EJBs, entretanto, teramos que mapear este objeto de negcio em pelo menos dois objetos:

    Figura 6.2 Objeto Separado em EJBs

    Note que estes objetos no fazem parte da anlise nem fazem sentido ao domnio. Para o usurio umamsica algo com ttulo, autor, gravadora, durao e ano que ele toca no rdio, explicar que este conceitofica dividido em duas metades e que o ato de tocar uma msica no gerenciado pelo mesmo componente

    que gerencia a prpria msica confuso. Como se no bastassem estes problemas, para cada EJB nsdevemos criar uma srie de arquivos de configurao e interfaces que no servem para nada mais quesatisfazer o framework.

    Nada impede que EJBs sejam utilizados sem esta estrutura. Podemos ter SessionBeans como Servicesquemanipulam POJOs, e DAOs JDBC ou um framework como Hibernate substituindo Entity Beans. Aindaassim existe a necessidade de adaptar a modelagem dos Servicesao framework EJB, criar vrios arquivosde configurao, interfaces remotas e etc.

    Utilizando POJOs

    A Figura 6.1 traz um exemplo claro de POJO. uma classe simples que representa um conceito denegcio e no est presa nenhum framework ou biblioteca.

    POJO (Plain Old Java Object) um objeto Java normal, que no implementa nem estende nenhuma classede 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 aplicaodevem 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 deobjetos integrados ao framework como EJBs e Servlets.

    Para no deixar que a infra-estrutura J2EE influencie diretamente sua aplicao e ainda assim obter asfuncionalidades 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 Figura6.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 outrasbaseadas em herana e frameworks intrusivos (como EJB).

  • 8/6/2019 Apostila Spring

    36/48

    !!"#"$"%$&'##((()

    7. Projeto de Aplicaes com SpringAlm de possibilitar o desenvolvimento baseado em POJOs, o Spring induz o uso de boas prticas quefazem esta abordagem realmente interessante. Duas destas prticas so: foco em interfaces e o uso de

    Domain Models.

    Programando para Interfaces

    Nos exemplos executados at agora tivemos sempre nossos beans implementados diretamente porclasses. O bom uso de Orientao a Objetos, entretanto, pede que os sistemas foquem em contratos, noem implementao.

    Uma interface um contrato a ser obedecido por uma classe. Ao implementar uma interface uma classe secompromete a implementar o comportamento descrito nesta interface. Ao vincular sua classe apenas aocontrato ao temos flexibilidade de mudar a implementao sem alterar as classes que dependem desta.Como exemplo, verifique o domnio abaixo.

    Figura 7.1- Domnio com DAONeste exemplo temos um GerenciadorLivros que utiliza um DAO para persistir os Livros. O DAO emquesto uma implementao exclusiva para lidar com banco de dados Oracle. O fonte doGerenciadorLivros fica parecido com o cdigo abaixo.

    publicclass GerenciadorLivros {

    private LivroDaoOracle livroDao = null;

    publicvoid setLivroDao(LivroDaoOracle livroDao) {

    this.livroDao = livroDao;

    }

    //mtodos de negcio

    }

    E este seria o applicationConfig.xml :

  • 8/6/2019 Apostila Spring

    37/48

    !!"#"$"%$&'##((()

    />

    Se quisermos que nosso sistema tambm possa utilizar MySQL, precisamos alterar oGerenciadorLivros como mostrado no diagrama abaixo.

    Figura 7.2- Alterando para MySQL

    Efetuando as mudanas destacadas no cdigo:

    publicclass GerenciadorLivros {

    private LivroDaoMySQL livroDao = null;

    publicvoid setLivroDao(LivroDaoMySQL livroDao) {

    this.livroDao = livroDao;

    }

    //mtodos de negcio}

    Alm da mudana no applicationContext.xml :

  • 8/6/2019 Apostila Spring

    38/48

    !!"#"$"%$&'##((()

    O simples fato de isolar a lgica de acesso a dados no DAO permite que o GerenciadorLivrospossa seralterado 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 cadamudana deste tipo, e este no o tipo de problema que ocorre apenas com mudanas drsticas como ade 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 oGerenciadorLivrosprecisa de um DAO para persistir os objetos. O problema que motiva a mudana de cdigo noGerenciadorLivros para mudarmos de banco de dados que da forma como est implementado hojeeste no depende de um DAO, ele depende do LivroDaoOracle especificamente (a nossa mudanaapenas 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 defato de um DAO qualquer criando uma interface genrica para DAOs.

    Figura 7.2- Alterando para MySQL

    Temos, ento, este cdigo no GerenciadorLivros :

    publicclass GerenciadorLivros {

    private LivroDao livroDao = null;

  • 8/6/2019 Apostila Spring

    39/48

    !!"#"$"%$&'##((()

    publicvoid setLivroDao(LivroDao livroDao) {

    this.livroDao = livroDao;

    }

    //mtodos de negcio

    }

    E agora para alterar o DAO utilizado basta configurar o applicationContext.xml de conforme osexemplos anteriores.

    Este mesmo princpio deve ser utilizado ao relacionar os beans de negcio, no apenas de infra-estrutura.Um bean deve depender do conceito representado por outro bean, no pela forma como ele estimplementado. Por exemplo, considere outro modelo de objetos.

    Figura 7.3 Catalogando CDs

    Neste exemplo temos o bean GerenciadorCds que depende de um servio de identificao de CDs.Atualmente esta identificao feita atravs de uma consulta ao CDDB (http://en.wikipedia.org/wiki/CDDB),um banco de dados disponvel na Internet com informaes sobre os CDs catalogados (o mesmo utilizado,por exemplo, pelo iTunes).

    Durante o desenvolvimento da aplicao, entretanto, no desejvel conectar a esta base de dados otempo todo. O desenvolvedor pode ter que parar de trabalhar porque a conexo com a Internet est comproblemas ou pode precisar ter controle sobre a resposta dada pelo CDDB para simular comportamentospossveis (o que acontece se no houver conexo? E se o CDDB retornar uma resposta formatada de

    maneira errada?).Mesmo se a aplicao for desenvolvida e estiver em produo existe a possibilidade de se alterar a formacomo os dados do CD so acessados. Imagine que passamos a catalogar CDs de bandas alternativas queainda no esto no CDDB, podemos precisar de um objeto que tente encontrar o CD no CDDB e caso noache procure em outro lugar. Ou podemos precisar manter informaes em cach local para minimizar asconexes via internet... todas estas alteraes vo acabar se refletindo em mudanas no cdigo doGerenciadorCds , o que no nem um pouco desejvel.

    Este o mesmo problema que tivemos com o DAO anteriormente e podemos resolve-lo da mesma forma.O GerenciadorCds no precisa especificamente do IdentificadorDeCdsCDDB , ele precisa de umIndentificadorDeCDs qualquer. Isso ns podemos modelar com uma interface.

  • 8/6/2019 Apostila Spring

    40/48

    !!"#"$"%$&'##((()

    Figura 7.4 O identificador de CDs genrico

    E assim como no exemplo do DAO para escolher qual identificador utilizar basta alterar oapplicationContext.xml .

    O padro do Spring, que ser utilizado deste ponto em diante neste texto, utilizar o sufixo Impl paraas implementaes quando o nome da interface coincidir com o da implementao, como no exemploabaixo:

    publicinterface GerenciadorAutores {

    //metodos de negocio

    }

    publicclass GerenciadorAutoresImpl implements GerenciadorAutores{

    //metodos de negocio

    }

    publicinterface GerenciadorEditoras {

    //metodos de negocio

    }

    publicclass GerenciadorEditorasImpl implements GerenciadorEditoras{

    private GerenciadorAutores gerenciadorAutores = null;

    publicvoid setGerenciadorAutores(GerenciadorAutores gerenciadorAutores) {

  • 8/6/2019 Apostila Spring

    41/48

    !!"#"$"%$&'##((()

    this.gerenciadorAutores = gerenciadorAutores;

    }

    // metodos de negocio

    }

    Configurados no applicationContext.xml desta forma:

    Padres de Modelagem de Domnio

    Ao modelar o Domain Model (veja ) da sua aplicao existem algum Padres quepodem ser observados. Eles definem alguns dos componentes bsicos de um Domain Model, as pedrasfundamentais para a modelagem de Regras de Negcio de maneira eficiente.

    O Spring Framework e outros containeres leves so ideais para o uso destes padres em Java. Segue umresumo destes padres, mais detalhes na bibliografia.

    Entity

    Entities (ou Entidades, nenhuma relao com Entity Beans) so objetos que possuem uma identidade nica.Um carrinho de compras numa loja virtual web no igual a outro. No importa que possuam os mesmosprodutos, o carrinho A o carrinho do usurio A, o carrinho B do usurio B. Mesmo que contenham osmesmos produtos voc no pode exibir o carrinho B ao usurioA, eles so diferentes! O carrinho nesteexemplo segue o Padro Entity., ele uma entidade de negcios nica.

    Value Object

    Nem todos os objetos precisam de identidade. Muitos objetos menores presentes em nosso modelo denegcios tm significado apenas pelo valor que possuem. Imagine um objeto que representa uma data,digamos 01/06/1979. Apesar de ser diferente de um objeto que representa a data 21/02/1983 igual a (epode ser utilizado no lugar de) qualquer outro que represente a mesma data que ele. Datas so geralmenteValue Objects, o que importa seu valor.

    Service

    Services so classes que no implementam diretamente as regras de negcio da aplicao, apenascoordenam a interao entre os componentes. Elas so quase sempre beans gerenciados pelo Springtodas as nossas classes GerenciadorXyz deste texto so Services. muito importante que Services no

    implementem as regras de negcio, apenas atuem como Faades coordenando as interaes.Repository

  • 8/6/2019 Apostila Spring

    42/48

    !!"#"$"%$&'##((()

    Um Repository onde os objetos ficam armazenados. Para as classes de negcio no importa se osobjetos so armazenados em arquivos XML, num banco de dados ou qualquer outro lugar, eles apenasprecisam que ao consultar o Repository possam obter estas classes. O Padro Data Access Object DAOgeralmente utilizado para implementar o Repository. O Repository quase sempre definido como uma

    interface implementada pelo DAO.Nota:A Sun publicou em seu Core J2EE Patterns um Padro chamado Value Object. Este Padro umaespecializao do PadroData Transfer Object posteriormente catalogado por Martin Fowler. Na segundaedio do livro a Sun alterou o nome deste para Transfer Object, porque Martin Fowler e Eric Evans jhaviam includo um Padro chamadoValue Object(que o descrito acima) em suas obras.

    Geralmente programadores Java se referem ao Transfer Object como Value Object. Alm do fato destanomenclatura estar desatualizada segundo o prprio catlogo de Padres oficiais de Java EE, TransferObjects no devem ser utilizados em sistemas que utilizam apenas uma JVM. Um TO utilizado destamaneira acaba com a Orientao a Objetos criando um design altamente Procedural. Este Padro foipublicado visando uso em sistemas onde Entity Beans trocam informaes numa rede.

    O diagrama abaixo mostra uma modelagem feita com estes padres.

    Figura 7.5 Modelagem utilizando Padres de Negcio

    Neste modelo temos o Usuario que possui Fotos como Entities. As regras de negcio estoimplementadas dentro destas Entities, como vemos abaixo:

  • 8/6/2019 Apostila Spring

    43/48

    !!"#"$"%$&'##((()

    public class Usuario {

    private Set contatos = new HashSet();

    private Set fotos = new HashSet();

    private Foto foto = null;

    private String login = null;

    public Usuario(String login) {

    super();

    this.login = login;

    }

    publicvoid setFoto(Foto foto) {

    this.foto = foto;

    }

    publicvoid adicionarContato(Usuario contato) {

    contatos.add(contato);

    }

    publicvoid removerContato(Usuario contato) {

    contatos.remove(contato);

    }

    publicvoid adicionarFoto(Foto foto) {

    fotos.add(foto);

    }

    publicvoid removerFoto(Foto foto) {

    fotos.remove(foto);

    }

    /**Retornatodasasfotosdesteusurioqueestopublicadasatualmente.*/

    public Set getFotosPublicadas() {

    Set fotosPublicadas = new HashSet();

    for (Iterator it = fotos.iterator(); it.hasNext();) {

    Foto foto = (Foto) it.next();

    if(foto.isPublicada()) fotosPublicadas.add(foto);

    }

    return fotosPublicadas;

    }

    public String getLogin() {

    returnlogin;

    }

    }

  • 8/6/2019 Apostila Spring

    44/48

    !!"#"$"%$&'##((()

    public class Foto {

    publicstaticfinalintRASCUNHO= -1;

    publicstaticfinalintPUBLICADA = 10;

    publicstaticfinalintDESPUBLICADA = 100;

    privateintstatus = RASCUNHO;

    private File arquivo = null;

    private String titulo = null;

    publicvoid setTitulo(String titulo) {

    this.titulo = titulo;

    }

    public String getTitulo() {

    returntitulo;

    }

    public Foto(File arquivo) {

    super();

    if (arquivo == null)

    thrownew IllegalArgumentException("Deve ser definido um

    arquivo!");

    this.arquivo = arquivo;

    }

    publicvoid

    publicar() {

    this.status = PUBLICADA;

    }

    publicboolean isPublicada() {

    returnthis.status == PUBLICADA;

    }

    public String getUrl() {

    String url = null;

    try {

    url = arquivo.toURL().toString();

    } catch (MalformedURLException e) {

    thrownew IllegalStateException("Problemas ao gerar URL dafoto", e);

    }

    return url;

    }

    }

    O que os Services fazem apenas coordenar o fluxo de interaes. Vamos ver a implementao da criao

  • 8/6/2019 Apostila Spring

    45/48

    !!"#"$"%$&'##((()

    de um novo usurio:

    publicclass GerenciadorUsuariosImpl implements GerenciadorUsuarios {

    private GerenciadorFotos gerenciadorFotos = null;

    private UsuarioRepository usuarioRepository=null;

    publicvoid 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;

    }

    publicvoid setGerenciadorFotos(GerenciadorFotos gerenciadorFotos) {

    this.gerenciadorFotos = gerenciadorFotos;

    }

    }

    publicclass GerenciadorFotosImpl implements GerenciadorFotos {

    private FotoRepository fotoRepository=null;

    publicvoid setFotoRepository(FotoRepository fotoRepository) {

    this.fotoRepository = fotoRepository;

    }

    public Foto enviarFoto(String titulo, File arquivo){

    Foto foto = new Foto(arquivo);

    foto.setTitulo(titulo);

    //processa o arquivo da foto

    arquivo.renameTo(new File(DIRETORIO_FOTOS, arquivo.getName()));

    arquivo.setReadOnly();

    fotoRepository.salvar(foto);

    return foto;

    }

    }

  • 8/6/2019 Apostila Spring

    46/48

    !!"#"$"%$&'##((()

    Por ltimo, os Repositories so implementados por DAOs que, neste exemplo fictcio, apenas escrevem natela:

    publicclass UsuarioDao implements UsuarioRepository{

    publicvoid salvar(Usuario usuario) {

    System.out.println("SALVANDO USUARIO ["+usuario.getLogin()+"]");

    }

    }

    publicclass FotoDao implements FotoRepository {

    publicvoid salvar(Foto foto) {

    System.out.println("SALVANDO FOTO [" + foto.getTitulo() + "]");

    }

    }

    Para unirmos todos estes objetos, contamos com o seguinte applicationContext.xml :

  • 8/6/2019 Apostila Spring

    47/48

    !!"#"$"%$&'##((()

    Exerccios

    1 No modelo apresentado na seo sobre Padres de Modelagem de Domnio, implemente afuncionalidade que permite aos usurios:

    a) Indicarem e removerem seus contatosb) Enviarem e removerem fotos

    c) Alterar sua foto de usurio

  • 8/6/2019 Apostila Spring

    48/48

    Bibliografia

    6&'$,0,$6=!

    &'##)#(>#1'&'?@,A0,

    B;,C

    D;,6D;,,$E,F6=G$+HI=""=%="%

    6&'$&,$6=!

    &'##)#(>#1'&'?@&,

    Calado, Phillip - Desenvolvendo Sistemas OO com Padres de Negcio MundoJava #17

    Editora Mundo

    J'67)K6+'',,6=%+H"%L%LG!"G

    E,6KH)&67F+'$