0

Programação Orientada a Aspecto (AOP em inglês)

Willams Sousa
Willams Sousa

Programação Orientada a Aspecto (AOP em inglês)


Olá, boa tarde,


O Spring Framework tem, pelo menos, duas partes importantes:

  • o container de gerenciamento de dependências que dá suporte a inversão de controle e injeção de dependências e,
  • o suporte a programação orientada a aspectos.


Este artigo pretende incitar a curiosidade sobre o tema. Veremos uma visão geral do é AOP e qual sua importância e faremos um exemplo de "Hello world AOP" para sentirmos de perto como funciona.


Idealmente nossas classes deveriam conter apenas as regras de negócio que diz respeito ao sentido da classe, então um martelo martela, um pincel pinta e uma cama é usada para dormir. Contudo, é comum que tenhamos algumas regras que serão usadas em várias classes dentro do sistema. Essas regras, como mostrado na imagem de capa do artigo, atravessam todo nosso sistema como uma transversal. Esse tipo de regra de negócio é ortogonal ao sistema, ela não se encaixa em nenhuma das classes, mas ao mesmo tempo tem relação com várias dessas classes. Podemos chamar esse fenômeno como 'aspecto'.


Como exemplos podemos ter, em um sistema que trabalha com figuras (retangulo, quadrado, triangulo, círculo) o aspecto 'mover', ou seja, todas essas figuras podem se mover. Outro exemplo pode ser o aspecto de validação de segurança, onde, em todo lugar que um User é usado queremos que ele seja validado se está autenticado e/ou autorizado. Ainda, podemos ter um aspecto que permite logar informações, ou mesmo um aspecto que detecta a velocidade com que cada método é chamado permitindo detectar gargalos. O principal aqui é que estes aspectos pertencem a várias classes e, portanto, são transversais, sendo difícil centralizá-los fazendo com que eles 'contaminem' vários locais no sistema e, com isso, forçando sempre uma grande atualização de código quando algo é modificado no aspecto.


Temos, até então, identificado o problema, agora veremos como a Programação Orientada a Aspecto e, consequentemente, o Spring Framework, nos ajuda a resolver o problema da 'transversalidade' de maneira elegante.


O AOP deve ser capaz de interceptar o código de qualquer parte do sistema introduzindo o aspecto desejado. Isso deve ser feito sem nenhum compromisso do código alvo. A ideia aqui é que as classes do sistema não dependam nem sequer conheçam a funcionalidade ou aspecto sendo aplicada. Essa estratégia permite plugar ou desplugar aspectos a qualquer momento. É possível que tenhamos uma equipe apenas para os aspectos e outra para as regras convencionais. P.ex., uma equipe pode ser responsável por gerenciar as funções dos usuários enquanto que outra gerencia a camada de segurança, de log e monitoramento. Como isso é possível? Sem mais mistérios, show the code!


Vamos ver o AOP funcionando de maneira objetiva.


No seguinte repositório: GitHub - osdeving/aopexample: A simple example of Spring AOP


vamos encontrar 3 classes: Agent, AgentAOP e AgentAOPDemo.


A classe Agent possui a seguinte função: imprimir (falar) "Bond".


Na classe AgentAOP temos nosso aspecto, perceba que implementamos a interface MethodInterceptor e no metódo recebemos um objeto do tipo MethodInvocation. Na prática o que isso significa é que dentro do método podemos fazer alguma coisa ANTES da função original ser chamada e alguma coisa DEPOIS da função original ser chamada. Para este exemplo decidimos imprimir "James" antes da função original (que sabemos que imprime "Bond") e imprimir "!" depois da função original. O importante aqui é entender que poderiamos, em vez disso, ter consultado o banco de dados, ter carregado algum recurso, ter consultado alguma API de validação, etc., tudo isso com o objetivo de efetuar alguma regra que não é estritamente conectada com a classe alvo.


Na classe AgentAOPDemo o mecanismo todo é executado:


public static void main(String[] args) { 
  Agent target = new Agent();
  ProxyFactory pf = new ProxyFactory(); 
  pf.addAdvice(new AgentDecorator()); 
  pf.setTarget(target); 

  Agent proxy = (Agent)pf.getProxy(); 
  
  target.speak(); 
  System.out.println(); 
  proxy.speak(); 
}       


A gente (o trocadilho não foi intencional!) instancia o objeto alvo (que, como já foi mencionado, é sempre inconsciente do aspecto que é aplicado a ele) e, a partir de um proxy (falarei mais sobre sobre depois) indicamos que esse objeto é o nosso alvo e que o AgentDecorator é nossa 'recomendação'. Com o alvo e a recomendação (para ser aplicada no alvo) gerenciadas pelo proxy, podemos chamar tanto a função do algo isolada, sem qualquer modificações, quanto a função do alvo *a partir do proxy*, ou seja, a função com o aspecto já aplicado.


Agora que temos em mãos um exemplo concreto para comparar, podemos voltar nossa atenção para alguns termos usados dentro da AOP.


jointpoint: um ponto bem definido durante a execução da aplicaçao. No caso do Spring será sempre uma chamada de método.


advice: é uma recomendação, é aquilo que você deseja que seja 'adicionado' ao comportamento original de um jointpoint. No caso do nosso exemplo, é imprimir "James" antes e "!" depois do jointpoint, que imprime "Bond".


pointcuts: a coleção de todos os jointpoints que você deseja aplicar um advice é conhecida como 'pointcuts', ou seja, todos os métodos que a gente aplicar a recomendação (advice) é conhecido como "pointcuts".


aspects: quando você tem um conjunto de pointcuts e um conjunto de advices encapsulado em uma classe você tem um aspecto. P.ex., você pode definir um aspecto que lida com segurança o qual envolve vários tipos de advices que são aplicados e vários jointpoints, essa 'funcionalidade' que atravessa seu sistema é um aspecto. Novamente, a ideia é que ela pode ser removida sem que o sistema sofra qualquer tipo de efeito colateral.


weaving: do verbo 'tecer', weaving é o que chamamos de 'costurador', é basicamente o cara (o código, a API ou framework) que costura o sistema entrando e saindo dos aspectos quando apropriado. Note que ao usar aspectos o seu sistema não é mais linear, isto é, ele executa o código fonte original e, quando existe um jointpoint ele 'entra' dentro de um aspecto e volta, fazendo parecer um zigzague de costura (sacou a ideia!?). O 'costurador' pode ser estático, fazendo as mudanças em tempo de compilação, ou mesmo dinâmico, onde a 'costura' é feita em tempo de execução.


target: é o alvo que vai ser 'advisado', no nosso exemplo, Agent é o nosso target.


A ideia aqui não é detalhar demais o tema, mas sim chamar a atenção para estudo posterior via artigos, tutoriais, livros, vídeos, etc.. Assim, vou finalizar o artigo falando um pouco sobre os proxys e decorators, cujo quais são a base da AOP.


Proxy


O proxy é um padrão de projeto onde você pega uma classe algo cuja função já está bem definida e envolve ela com uma nova funcionalidade. Para ficar mais claro, imagine que você tenha uma classe DAO, essa classe tem a função de carregar registros do banco, salvar, atualizar, deletar, etc., ela faz o famoso crud.

Digamos que você detectou que o sistema está lento e que seria interessante implementar um cache, onde os registros que foram buscados no banco fiquem na memória para, caso uma nova pesquisa for feita, ela obter os registros da memória e não do banco.

Para incluir essa nova função você pode criar uma classe CacheDAOImpl que envolve a classe DAO e, caso você siga as boas práticas e DAO é uma interface, você poderá continuar usando DAO, só que dessa vez tendo como implementação a CacheDAOImpl e não a DAOimpl.


Decorator


O Decorator é um padrão de projeto semelhante ao Proxy, porém ele melhora a interface do objeto decorado. Em outras palavras, enquanto que a adição que o proxy faz é opaca para o cliente, a adição do decorator é transparente. Em nosso exemplo, AgentDecorator é um agent 'diferente'.



Referências:


Pro Spring 5 by Iuliana Cosmina, Rob Harrop, Chris Schaefer and Clarence Ho pela Apress

(chapter 05 - Introducing Spring AOP)

Padrões de Projeto / Design patterns (refactoring.guru)


Design Patterns com Java by Eduardo Guerra pela Cassa do Código

0
0

Comentários (0)

Tento ser um sujeito legal e gosto de aprender linguagens de programação.

Brasil