Archive for Agosto 2008
AOP utilizando @AspectJ e Spring
Nesse artigo vou explicar os conceitos básicos de AOP e mostrar um exemplo inicial de como isso é feito utilizando @AspectJ 5 e Spring.
A Programação Orientada a Aspectos (AOP) complementa a programação orientada a objetos, provendo uma nova forma de pensar sobre a arquitetura da aplicação.
Na programação orientada a objetos encapsulamos as responsabilidades em classes. Já na AOP, as responsabilidades são encapsuladas em um aspecto. Um aspecto permite a modularização de interesses que geralmente aparecem espalhados por várias classes do sistema (denominados de interesses transversais – crosscutting concerns), como o gerenciamento de transações, por exemplo.
Veja a imagem abaixo. Se compreendermos as linhas horizontais como classes, veremos que os interesses de segurança, transação, etc. são transversais, ou seja, repetidos entre várias classes. A AOP contribui no sentido de retirar essas funcionalidades das classes e encapsula-las em aspectos, sem alterar o comportamento do sistema.

Conceitos
Aspect: é a unidade modular (funcionalidade) que encapsula interesses que atravessam vários objetos dentro do sistema.
Join Point: é um ponto durante a execução do programa que poderá ser afetado pelo aspecto. Um join point pode ser, por exemplo, a execução de um método do programa.
Point Cut: é uma expressão escrita em uma linguagem específica para a finalidade de selecionar join points (pontos de execução).
Advice: quando um join point é atingido, e selecionado pelo point cut, uma ação será executada. Essa ação é determinada advice.
Objeto Alvo: é o objeto que está sendo interceptado por um ou mais aspectos.
Proxy AOP: é o objeto criado pelo framework AOP para implementar a ligação entre o aspecto e o objeto alvo.
Veja na imagem abaixo. Durante a execução do programa, vários join points serão “atingidos”. No suporte a @AspectJ do Spring Framework (veremos exemplos a seguir) um join point é sempre a execução de um método. Dessa forma, imagine que cada um dos 6 join points abaixo representem 6 diferentes métodos. Um point cut é uma expressão, em linguagem específica, que seleciona quais dos 6 métodos (join points) serão afetados pelo aspecto. Nesse caso, imagine que os 3 joint points verdes foram atingidos pela expressão pointcut. O advice é a ação que irá executar quando eles foram atingidos, nesse caso, o advice será executado 3 vezes.

Tipos de Advice
No AspectJ existem 5 tipos diferentes de advice:
- Before: ação do advice executa antes do join point.
- After returning: ação do advice executa depois do joint ser executado com sucesso, ou seja, sem lançar exceção.
- After throwing: ação do advice executa depois do joint ser executado com erro, ou seja, somente quando ele lançar uma exceção.
- After (finally): ação do advice executa depois do joint ser executado independente de ter causado ou não exceção.
- Around: advice que envolve a execução de um joint point. Com ele é possível codificar ações antes e depois do join point. Inclusive é possível alterar valores passados como parâmetro, como retorno, ou nem mesmo chamar o método do objeto alvo.
Exemplo concreto utilizando o suporte a @AspectJ com Spring
A partir da versão 2.0 do Spring Framework é suportado o uso do @AspectJ 5 de forma integrada ao seu container. Ainda é possível declarar aspectos por XML, como nas versões anteriores, porém agora é possível declarar aspectos com uso de anotações.
Para implementar um aspecto é necessário três coisas:
- Colocar os jars ‘aspectjrt.jar’ e ‘aspecjtweaver.jar’ no classpath, juntamente com os jars tradicionais do Spring.
- Declarar no applicationContext.xml o uso de aspectos com declaração por anotações, dessa forma:<aop:aspectj-autoproxy />.
- Criar uma classe anotada com @Aspect para definir o aspecto. Utilizar uma anotação de advice (before, after ou around) e definir uma expressão point cut para selecionar quais joint points o aspecto afetará.
Veja um exemplo abaixo:


Repare que a expressão “execution(* xyz.abc.ClienteDao.*(..))” é o point cut e a anotação @Before é o advice. A linguagem do point cut é específica do @AspectJ e sua documentação pode ser encontrada no site da biblioteca. Explicando a expressão em detalhes:
- execution: Qualquer execução de método.
- Primeiro asterisco da expressão: que tenha qualquer visibilidade e retorne qualquer tipo de parâmetro.
- xyz.abc: pacote que estão a(s) classe(s) que o point cut afetará.
- ClienteDao: a classe afetada pelo point cut.
- Segundo asterisco da expressão: qualquer método da classe ClienteDao.
- (..): O método pode ter qualquer quantidade de parâmetros, de qualquer tipo.
Dessa forma podemos dizer que o método ‘realizarAcao’ será executado antes que qualquer método da classe ClienteDao executar.
É importante lembrar que o suporte à @AspectJ do Spring, como mostrado no exemplo, só selecionará join points que forem beans gerenciados pelo Spring. Ou seja, no exemplo acima o ‘ClienteDao’ tem que ser um bean no application context do Spring.
No próximo artigo veremos como implementar uma solução simples de auditoria utilizando AOP com Spring e @AspectJ.
Abraços,
Michel Zanini.
Customizando beans com BeanPostProcessor
O container de injeção de dependências do Spring Framework foi criado para ser extensível. Tipicamente, não existe nenhuma razão para um desenvolvedor estender ou customizar alguma classe da hierarquia encabeçada pelas interfaces BeanFactory e ApplicationContext.
Um ponto muito utilizado para extensão da lógica de configuração do container IoC são os BeanPostProcessor’s. Essa interface dispõe de alguns métodos de “callback” que permitem customizar a lógica de instanciação e resolução de dependências. Se você precisa realizar algum trabalho logo após um componente (bean) ser instanciado, esse é um bom lugar para isso.
Um BeanPostProcessor é tratado de forma especial pelo container. Um bean desse tipo é instanciado antes de todos os outros. Quando um bean “convencional” for instanciado, os BeanPostProcessor’s configurados serão executados de acordo com a ordem definida.
A interface possuí dois métodos de callback. Um dos métodos (postProcessBeforeInitialization) é executado antes de qualquer outro ponto de extensão (afterPropertiesSet ou init-method) e o outro (postProcessAfterInitialization) é executado após o afterPropertiesSet e init-method. Veja na imagem abaixo para entender o ponto em que os métodos da interface BeanPostProcessor são chamadas (destaque em vermelho):

Agora vamos fazer um exemplo prático para entender melhor a idéia. Vamos implementar um BeanPostProcessor para fornecer um serviço de log para qualquer spring bean que necessite, de forma automática, sem necessidade de injeção.
Primeiro implementamos uma Interface chamada de LogAware com apenas um método disponível: setLog(org.apache.commons.logging.Log):

Agora vamos implementar o BeanPostProcessor que atua na inicialização dos objetos para injetar o log automaticamente em beans que implementam a interface acima:

Um bean que implementa a interface LogAware, como no exemplo abaixo, recebe a injeção do log automaticamente na fase de inicialização do objeto. Pois como o LogInjectingBeanPostProcessor foi declarado no applicationContext.xml, todas as instanciações de spring bean’s passarão por ele.

Veja logo abaixo o applicationContext.xml com os beans declarados. Repare que um BeanPostProcessor apenas precisa ser declarado no xml e é automaticamente registrado pelo Spring.

Agora vamos melhorar nosso exemplo para excluir a necessidade de uma interface a ser implementada, vamos substituí-la por uma anotação @Logger. Isso facilitará o desenvolvimento porém diminuirá um pouco a performance na inicialização do container. Veja a remodelagem do LogInjectingBeanPostProcessor para utilizar reflection e injetar o Log em um atributo que possui a anotação @Logger:

Agora o bean de exemplo ficou bem mais simples. Ele não implementa mais a interface, em troca disso utiliziamos a anotação. Na anotação é possível especificar uma string que será utilizada como nome do logger, caso nada for especificado, será utilizado o nome completo da classe.

Como vimos, um BeanPostProcessor pode adiantar muito a vida dos desenvolvedores trazendo um ponto
importante de customização e extensão. É claro que o exemplo dado não é muito útil. Existem maneiras mais simples de ter acesso a uma API de log. Porém a mesma idéia pode ser utilizada em vários outros casos.
Abraços.
Michel Zanini.
Spring MVC
Olá! Faz muitos dias que não escrevo aqui mas, vamos lá.
Encontrei esse excelente artigo sobre o framework web Spring MVC na InfoQ.
Para quem, como eu, não sabe ao certo qual framework web mais lhe agrada (ou desagrada) vale a pena dar um olhada. Em especial, no excelente trabalho feito pelo Spring MVC em facilidade de configuração e capacidade de assumir excelentes valores default.
Abraços,
Michel Zanini.