Posts Tagueados ‘aop’
AOP na prática: implementando um aspecto de auditoria
No último artigo apresentei os conceitos básicos da Programação Orientada a Aspectos. Nesse artigo pretendo mostrar um exemplo prático de um problema muito comum em aplicações “enterprise”, a auditoria.
A auditoria é o processo de registrar todas as mudanças feitas pelos usuários para que se possa provar as ações tomadas por eles. Dessa forma é possível provar que o sistema não estava errado. Por exemplo, os dados sumiram porque alguém os excluiu.
Auditoria é uma responsabilidade “cross-cutting”, ou seja, se for programada de maneira tradicional estará espalhada por todo o sistema. Entretanto, é possível implementar tal funcionalidade utilizando técnicas de AOP, como veremos a seguir.
Dando continuidade ao artigo anterior, os exemplos estarão utilizando Spring e @AspectJ.
Exemplo Inicial
Começamos definindo uma interface geral para que nossos objetos de acesso ao banco de dados possam implementar, seguindo o padrão de projeto “Data Access Object”.

Utilizamos o recurso de tipos genéricos para que nossas implementações possam inserir qualquer tipo de objeto do domínio.
Para não complicar o exemplo a implementação da interface apenas imprimirá no console para sabermos que o método foi executado, porém imagine que poderíamos estar executando código JDBC ou Hibernate/JPA em seu lugar.

Agora implementaremos a primeira versão do nosso aspecto de auditoria, que simplesmente irá interceptar as execuções dos métodos inserir, atualizar e remover, imprimindo no console uma mensagem de aviso.

Note o uso do advice @AfterReturing para que o aspecto seja aplicado após uma execução com sucesso do método alvo. No pointcut interceptamos execuções de métodos de objetos que implementam a interface EntityDao, como a classe ConsoleClienteDao que criamos acima.
Para completar o exemplo mostramos o applicationContext.xml e o método Main para teste da aplicação.


A execução do método main irá imprimir o seguinte no console:
executou inserirCliente
depoisDeInserir
executou atualizarCliente
depoisDeAtualizar
executou removerCliente
depoisDeRemover
Agora, de posse de um exemplo muito simples, iremos melhora-lo para contemplar funcionalidades mais reais.
Auditando dados da entidade
Vamos criar uma superclasse abstrata para nossas entidades, dessa forma podemos utilizar o aspecto para obter informações de auditoria.

A classe Entity possui um id e um método a ser implementado pelas subclasses para obter uma String descritiva para auditoria. Em um sistema real poderíamos criar um POJO para substituir a String, de forma que ele poderia conter informações mais avançadas. Agora nossa classe Cliente passa a estender a classe Entity.
Para ter acesso aos dados da entidade que está sendo auditada podemos utilizar a expressão ‘args’ da sintaxe de pointcut do @AspectJ. Veja o exemplo abaixo.

Agora restringimos o método inserir a ter apenas um parâmetro, e do tipo Entity. Na expressão args(entity) definimos o nome do parâmetro, essa string deve coincidir com a variável declarada como parâmetro do método depoisDeInserir. Sendo assim, o objeto disponibilizado para o método é o mesmo passado como parâmetro do ConsoleClienteDao, e podemos utiliza-lo para auditoria.
Outra forma possível de auditar os dados da entidade seria utilizar a API de reflection para obter todas as suas propriedades, e então, montar uma descrição com a concatenação de seus valores.
Auditando mudanças nas atualizações
Em geral na auditoria, quando um objeto sofre um update, é desejável auditar as mudanças realizadas. Mas como podemos saber as mudanças feitas antes do update ocorrer? Podemos fazer um select antes e comparar os dados antes e depois da atualização.
Isso pode ser facilmente contemplado utilizando um advice @Around. Antes da execução do método atualizar fazemos um select e obtemos o objeto em seu estado atual, depois da atualização com sucesso, comparamos os dois objetos utilizando reflection (ou alguma interface), e então, auditamos o resultado.

Para manter os exemplos simples apenas comparamos os objetos com o método equals. Alem disso, nenhum tratamento foi feito para evitar NullPointerExceptions. Note que o método proceed executa o método alvo e em caso de exceções, será propagado para fora do aspecto, sem chegar a executar as ultimas linhas do método.
Filtrando quais classes participarão da auditoria
Imagine que para uma determinada aplicação é necessário fazer auditoria em apenas alguns DAO’s. Mas queremos que nosso aspecto continue consistente, ou seja, não sofra alterações constantemente. Para tal, uma idéia interessante é a utilização de anotações para marcar o pointcut do aspecto. Veja o exemplo abaixo.

Veja a expressão @target(exemplo.AptoParaAuditoria). Essa expressão significa que para o pointcut ser atingido a classe alvo tem que estar anotada com a anotação @AptoParaAuditoria. Dessa forma, a auditoria só ocorre quando desejado, nos DAO’s marcados com essa anotação. Também é possível criar filtros a nível de método utilizando a expressão @annotation(exemplo.AptoParaAuditoria).
Para melhorar o exemplo ainda é possível criar um atributo na anotação, uma enumeração, para informar em quais operações serão auditadas: inserir, atualizar, remover ou todas.
Obtendo informações do usuário corrente
Em um sistema de auditoria não basta saber o que foi feito e onde, também é necessário saber quem fez a alteração. Ou seja, é necessário obter dados do usuário logado. Em uma aplicação web isso se torna difícil, pois é impossível obter um objeto HttpRequest ou HttpSession de dentro do aspecto de auditoria.
Para essas situações existe uma técnica muito utilizada na AOP, associar recursos a Thread corrente. Assim é no Spring na área de controle de transações. Quando uma transação é aberta pelo aspecto de transação é associado a Thread corrente um java.sql.DataSource ou, no caso do Hibernate, uma org.hibernate.classic.Session. Dessa forma, ao longo da execução da Thread, de todos os lugares, é possível obter o mesmo recurso de conexão (na mesma transação), para executar o acesso ao banco de dados.
Essa solução pode ser aplicada nesse caso. Podemos implementar um filtro http (javax.servlet.Filer) que associa o request a Thread corrente. Dessa forma, de dentro do aspecto, podemos acessar o HttpRequest. Na verdade, o Spring já possui tal filtro implementando dentro do spring-web.jar, basta declararmos no web.xml.

Agora de dentro do aspecto de auditoria é possível acessar o request e a session desta forma:

Conclusão
A Programação Orientada a Aspectos é muito útil para funcionalidades como auditoria provendo sempre uma solução transparente. O Spring já nos traz vários recursos implementados que se utilizados de forma correta podem poupar muitos esforços. O @AspectJ está muito bem integrado com o Spring Framework, e o casamento das duas tecnologias pode trazer grandes benefícios.
Abraços,
Michel Zanini.
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.