Aspect-Oriented Programming e Middleware
Conceitos
AOP veio para complementar OOP provendo uma nova forma de pensar a respeito da estrutura de um programa.
- OOP: Programas são decompostos em hierarquias de objetos.
- AOP: Programas são decompostos em aspectos ou preocupações (também chamadas de interesses).
AOP não veio para substituir OOP, mas sim para melhorar a modularidade de programas de uma forma mais geral, separando melhor algumas preocupações que em geral cortam muitos pontos de um programa.
A seguir algumas definições importantes relacionadas a AOP:
- Preocupação: Uma preocupação ou interesse é uma questão, conceito, ou área de interesse relativa a uma aplicação. Exemplos: segurança e gerência de transações.
- Preocupação transversal (Crosscutting Concern): É uma preocupação cuja implementação atravessa muitas classes.
- Aspecto: É a modularização de uma preocupação transversal.
- Ponto de Junção (Joinpoint): Um ponto durante a execução de um programa, como a invocação de um método, o acesso a um campo, o lançamento de uma exceção.
- Advice: O Advice ou "conselho" é uma ação a ser tomada em um ponto de junção particular, como uma checagem de segurança antes da execução de determinados métodos.
- Ponto de Corte (Pointcut): Corresponde a um conjunto de pontos de junção e é usado para definir quando um advice deve ser ativado.
- Introduções (Introduction): É a adição de métodos ou campos a uma classe ou interface Java já existente. Também pode ser usada para fazer com que uma classe existente implemente uma interface sem alterar o seu código fonte.
- Mixin inheritance: É uma forma de fazer com que uma classe encapsule funcionalidades de classes sem usar herança convencional.
- Weaving (tecer, trançar): É a junção dos aspectos a um fluxo de execução completo ou à uma classe completa.
Há três tipos de "advice":
- Before (pre): Antes que um ponto de junção seja invocado.
- After (post): Após a invocação do ponto de junção, ocorrendo ela com sucesso (after returning), sem sucesso (after throwing) ou em qualquer dos dois casos (after).
- Around: O advice tem o controle do ponto de junção podendo invocá-lo ou substituí-lo por completo.
AOP e Design Patterns
É importante destacar que alguns padrões de projeto OO resolvem alguns dos problemas que AOP tenta atacar:
- Decorator: Permite a adição de comportamento customizado antes e depois de uma invocação de método.
- Observer: Permite que múltiplos objetos recebam notificações de eventos relativos a um objeto "observável".
- Chain of Responsibility : Permite que múltiplos objetos em uma corrente recebam uma requisição até que algum assuma a responsabilidade de tratá-la.
AOP e J2EE
EJB pode ser usado para tratar de forma declarativa algumas preocupações já predefinidas, como gerência de transações.
Pode-se também usar filtros de servlets para execuções antes e depois de requisições HTTP, mas bem vinculadas a API de servlets.
Pode-se usar também um framework como o Web Work 2 que provê a capacidade de interceptação, mas isso é menos geral do que um framework AOP de verdade. Só se vai poder colocar serviços declarativos em certas invocações gerenciadas pelo framework.
EJB como um subconjunto de AOP
EJB é em parte uma forma menos geral de interceptação AOP, usada para acessar um conjunto fixo de serviços J2EE providos por um servidor de aplicação.
Um aspecto em EJB já vai empacotado com o contêiner EJB, que já provê alguns serviços. Um join point em EJB é a execução de um método na interface de um componente EJB. Pointcuts são especificados no EJB deployment descriptor. Eles são descritos estaticamente, em termos de nomes de métodos e opcionalmente na forma de listas de argumentos. O servidor EJB tipicamente faz o weaving dos aspectos, tanto através de geração de código (gerando uma subclasse da classe de implementação do EJB em tempo de deploy e compilando-a) quanto introduzindo um proxy dinâmico ou alguma forma de geração de bytecode.
É importante destacar, porém, que o modelo de interceptação do EJB é mais limitado:
- Um advice só pode ser aplicado a um EJB.
- Limitação no modelo de pointcuts (ex: não consegue especificar um advice para o momento de uma exceção).
- Pointcuts não podem levar em conta informações dinâmicas.
- Não é possível adicionar ações customizadas usando EJB padrão (JBoss 3 tentou adicionar isso).
- É impossível mudar a implementação de qualquer dos interceptadores além dos parâmetros de configuração que são expostos pelo servidor de aplicações.
EJB provê um prato feito: Coma tudo o que o chefe preparou,
quer goste ou não.
AOP oferece uma refeição à la carte: Coma o que quiser, mesmo
que tenha de ser pedido em outros restaurantes.
Estratégias de Implementação AOP
Dynamic Proxies
São construções de Java 1.3+ que nos permitem criar uma implementação de um ou mais interfaces em tempo de execução. Para implementar um around advice com um dynamic proxy, este deve invocar a corrente de interceptadores necessários. O último invocará um objeto destino (se existir algum) via reflexão.
O Spring usa dynamic proxies quando está lidando com o "proxying" de interfaces. O Nanning usa dynamic proxies exclusivamente.
Vantagens:
- Uso da linguagem Java padrão.
- Não é necessária uma biblioteca de terceiros além do framework AOP.
- Sem risco de efeitos estranhos no comportamento do servidor de aplicações.
Limitações:
- A impossibilidade de fazer o proxy de classes (ao invés de interfaces).
- Overhead da reflexão.
Usado por:
- Spring (quando tratando interfaces)
- Nanning
Geração Dinâmica de Byte Code
Para fazer o proxy de classes, ao invés de apenas interfaces é necessária a geração dinâmica de byte code. Exemplo de ferramenta para esse fim: CGLIB (Code Generation Library), usada pelo Spring, onde se obtém interceptação via geração de subclasses dinâmicas. A limitação dessa abordagem é que não se vai poder fazer proxy de métodos final.
Geração de Código Java
Abordagem que parece estar caindo em desuso devido aos dynamic proxies e por geração de byte code dinâmico ser mais simples de se trabalhar.
Uso de um Class Loader customizado
Para interceptar todas as instâncias de uma classe particular ou para mudar o construtor de uma classe deve-se investigar o mecanismo de carregamento de classes de Java, onde se pode definir um class loader customizado. Algumas vezes carrega-se informações de arquivos XML de configuração.
Usado por:
Limitação:
- Risco de se fugir de Java padrão.
- Pode ser problemático em alguns servidores de aplicação.
Extensões da Linguagem
Obtem-se através de uma linguagem focada em AOP, como AspectJ, que é uma extensão orientada a aspectos de Java.
Implementações AOP
AspectJ
- É a mais completa implementação de AOP.
- Não usa metadados para definir pointcuts.
- Pointcuts podem ser baseados em vários critérios, incluindo o uso de coringas e de "control flow".
- Weaving acontece em tempo de compilação.
- Advices são aplicados a objetos, tendo sido eles construídos ou obtidos.
- Tem habilidades únicas como a de modificar a estrutura estática de tipos, declarar erros e warnings em tempo de compilação e "soften" exceptions.
- Porém, não é apontada como a melhor escolha para a maioria das aplicações J2EE por alguns problemas como os seguintes:
- Sintaxe complexa
- Risco de introduzir uma nova linguagem numa organização
- Não se pode ainda configurar pointcuts em arquivos XML (talvez isso mude nos novos releases).
- Não há o conceito de "per instance" advice.
- Não se pode adicionar ou remover advices em tempo de execução.
- O poder excessivo oferecido por AspectJ pode ser poderoso
AspectWerks
- Framework AOP puro, que define pointcuts em arquivos XML.
- Dá suporte a advices "per JVM", "per class", "per instance" e "per thread"
- Há advices do tipo "pre", "post" e "around"
- Também oferece o advice "throws"
- Weaving em tempo de execução com uma abordagem baseada no class loader.
JBoss 4
- AOP é um dos recursos-chave do JBoss4.
- JBoss AOP está disponível para os projetos que usam JBoss como seu servidor de aplicações J2EE.
- O grupo JBooss visualizam os aspectos como "as jóias da coroa" do middleware.
- Objetivam usar AOP para simplificar o uso de serviços providos pelo servidor de aplicação.
- O framework do JBoss é baseado do controle do class loader.
- Usa XML para a definição de pointcuts.
- Provê um console de gerência mostrando o controle de configuração e os aspectos escolhidos.
- Integração com o servidor de aplicação JBoss para oferecer aspectos pré-fabricados.
- Forte acoplamento com o framework AOP do JBoss e com este servidor de aplicação, devido ao controle sobre o class loader.
- Formato de configuração via XML relativamente complexo.
- Atributos de metadados podem ser apenas Strings e fragmentos XML.
Spring
- Integra o suporte AOP a sua infra-estrutura de "container light".
- Vários tipos de advice: around, before, after e throws
- Suporte a introductions e mixins.
- Modelo de pointcuts expressivo e extensível.
- Aspectos são normalmente configurados em arquivos XML.
- Advices devem implementar org.aopalliance.aop.Advice.
- Um advisor é um conceito de alto nível do Spring para expressar advice e pointcuts.
- Introductions são feitas usando IntroductionAdvisors.
- Spring AOP é portável entre diferentes servidores de aplicação.
- Não suporta interceptação de campos.
- Só se pode interceptar objetos obtidos através do Spring IoC container.
- Exemplo de interceptador:
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class DebugInterceptor implements MethodInterceptor{
public Object invoke (MethodInvocation invocation) throws Throwable {
System.out.println("Debug interceptor: invocation=["+invocation+"]");
Object rval = invocation.proceed();
System.out.println("Debug interceptor: next returned");
return rval;
}
}
Nanning
- Nanning Aspects é o framework mais parecido com o Spring.
- Não oferece a interceptação de campos e usa proxies dinâmicos.
- Enfatiza um estilo de programação para fazer a interceptação e alteração do comportamento de objetos ao invés de uma abordagem direcionada a configuração.
The AOP Alliance
- Provê interfaces padrões para um subconjunto de funcionalidades AOP.
- Tem tido problemas em padronizar AOP.
- Spring, Dynaop e JAC implementam as interfaces de interceptação e o suporte do Nanning está sendo feito.
Alguns Desafios de AOP
Perigos oferecidos
- Interceptação de campos imprópria
- Aspectos demais
- Interdependência entre aspectos
- Dificuldades para se testar
- Debugging
- Efeitos na performance
Referências
- J2EE Development without EJB. Rod Johnson with Juergen Hoeller.