Escolar Documentos
Profissional Documentos
Cultura Documentos
Diego Pacheco
Dezembro/2007
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Sumário
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Objetivos
• Conhecer os conceitos básicos sobre AOP/AspectJ
• Conhecer o conceito de Concern e Crosscuting Concern
• Conhecer a estrutura básica de um aspecto
• Conhecer os pilares do AspectJ
• Conhecer como funciona o mecanismo padrão de weaving do AspectJ
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Conceitos Básicos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
• Menos coeso
• Menos legível
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Os aspectos acabam com o dilema over design vs under design, este dilema se norteia
no seguinte princípio: desenvolver um wrapper em cima de algum framework como por
exemplo o Log4J ou usá-lo de maneira pura. Essa questão pode criar dois resultados
distintos, no primeiro over design, nós usamos o framework de maneira pura e, se
precisarmos alguma funcionalidade adicional vamos ter um retrabalho. A outra
auternativa under design, desde o inicio usamos um wrapper para o framework, o que
pode acontecer é que não exista necessidade e por isso trabalharemos à toa. O Uso de
POA elimina este problema.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Pilares do AspectJ
O AspectJ possui “classes” como na linguagem Java, porém com mais recursos
ao desenvolvedor, essas “classes” são chamados de Aspects. Os aspectos tem entidades
especiais que não existem nas classes Java comuns, são elas:
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Aspects
// Pointcuts
// Advices
O Aspecto pode estar dentro de um package, regido pelos mesmos padrões Java,
também é possível acessar qualquer recurso Java de dentro de um aspecto, este
aspecto pode importar classes através da diretiva import, assim como em uma classe
java. Depois vem a visibilidade do aspecto (public por exemplo) seguida por um nome,
esse nome deve obedecer os padrões Java de nomes de classes.
Dentro do aspecto ficam as definições, as expressões para join points, essas expressões
são os pointcuts, podemos ter diversos pointcuts em um aspecto, desde que eles
tenham nomes diferentes.
No final ficam os advices, é possível ter multiplos advices para um mesmo aspecto,
dentro dos advices é possível executar qualquer código Java.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Mecanismos de Weaving
• Modificar a JVM:
Vantagens:
• Mais performático
Desvantagens:
• Perda de portabilidade
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
• Load Time:
Vantagens:
Desvantagens:
• Mais lento
• Compile time
Vantagens:
Desvantagens:
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
4. Com esses dois bytecodes é gerado o weaving, que é mistura dos dois códigos.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
5. Finalmente é gerado um único bytecode contendo aspectos e código Java, não
quebrando a especificação bytecode Java e ao mesmo tempo atendendo os
requisitos funcionais do AspectJ.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Exercícios
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
2. Pointcuts
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Objetivos
• Saber utilizar pointcuts com call e execution
• Saber utilizar anotações para aspectos
• Saber realizar expressões pointcut considerando anotações
• Saber declarar warnigs e erros
• Saber realizar injeção de anotações
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Pointcuts
Pointcuts são alguns join points de um programa que são capturados pelo mecanismo
de AOP do AspectJ. No AspectJ existem 11 possíveis join points, veja:
• Chamada de método
• Execução de método
• Chamada de construtor
• Execução de construtor
• Pre-inicialização
• Inicialização
• Inicialização estática
• Handler
Exemplo:
package br.com.targettrust.aop.pointcuts;
No exemplo acima estamos declarando um pointcut de nome nomePointcut que irá capturar
todas as chamadas ao método metodoX() de qualquer classe.
Quando montamos as expressões dos pointcuts podemos utilizar operadores lógicos para
juntar mais de uma expressão. O AspectJ disponibiliza os seguintes operadores lógicos: &&, || e
!. Veja no exemplo a baixo como usar cada um.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.pointcuts;
No exemplo acima foi demostrado o uso dos três operadores lógicos para pointcuts, é possível
combinar ou usar quantas vezes forem necessárias estes operadores. Ainda é possível fazer
com que um pointcut capture mais de um método e de várias classes de seu sistema, quanto a
isso não existem restrições.
As expressões dos pointcuts ainda suportam o wild card *. Esse wild card pode ser utilizado
para os casos em que não queremos informar o nome completo de um pacote, classe ou
método. Ex.: supondo uma classe de negócio que tem os métodos findCliente(),
findClienteByName(), findClienteByCpf(), findClienteByTelefone() neste caso, poderíamos com
uma única expressão pegar todos estes métodos, o código AspectJ ficaria assim:
No exemplo acima estamos informando que queremos capturar todos os métodos find* que
recebam quaisquer parâmetros e que retornem qualquer coisa. Nesse exemplo aparece a
propriedade: “..” que neste contexto significa qualquer parametro ou seja, de 0..* e com
qualquer tipo de dado.
Outro recurso interessante é o pointcut primitivo cflow(), com ele podemos pegar a execução
de outros pointcuts, por exemplo o pointcut: pointcut x(): call (* exec*(..)); se fizermos
cflow(exec()) significa que enquanto o metodo exec() estiver executando alguma operação
poderá ser feita. Quando ele para de executar esse ponto se torma inválido.
Esse recurso é muito útil , pois podemos fazer controles enquanto algo está em execução ou
enquanto algum método ainda não foi executado.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Para os 11 joinpoints, os pointcuts equivalentes são: call, execution, get, set, preinicialization,
inicialization, staticinicialization, handler e adviceexecution.
Call VS Execution
Para capturar a execução de um método podemos utilizar tanto o operador call como o
operador execution. Porém existem algumas diferenças dos mesmos.
Outro aspecto importante é que o call não captura chamadas de procedências superiores para
métodos não estáticos, ou seja, somente para métodos da própria classe e os métodos que
estejam em uma classe pai, porém, que sejam estaticos.
A regra geral é: se você deseja capturar algum trecho de código em particular para realizar
algum tracing por exemplo, utilize execution. Mas se você deseja capturar um método com
uma assinatura particular que normalmente é utilizado em aspectos que vão para produção,
utilize call.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
A versão 1.5.X do AspectJ prove suporte completo aos recursos do Java 5.0 como:
varargs, anotações, retorno co-variante, enumerations, generics e autoboxing.
O AspectJ prove um set muito rico de recursos para anotações que serão bem detalhadas na
sequência. Os recursos de auto-boxing são transparentes para o AspectJ, ou seja, não há
diferenças em join points, pointcuts ou advices entre primitivos e wrappers. Exemplo:
args(Integer) ou args(int) são equivalentes.
Pegaria a criação de todos os objetos do pacote xyz que tiverem no construtor um varargs de
Foo ou Goo.
Atenção: Quando utilizamos varargs a syntax é <<Tipo>>..., não confunda essa syntax com os
recursos do próprio AspectJ(..). O recurso .. captura quaisquer argumentos.
No que diz respeito aos recursos de enumerations é exatamente igual ao Java, a mesma sintaxe
e as mesmas limitações.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
• Runtime: São lidas pelo compilador, vão para o class gerado e ainda
podem ser obtidas em tempo de runtime.
Por padrão annotations não são herdadas no mecanismo padrão de herança do Java.
Mas é possível fazer herança utilizando a annotação @Inherited.
O AspectJ Prove anotações bem como alternativa a sua syntax de aspectos, existe um
conunto de annotation para a utilização do AspectJ .
No Java 5.0 quando usamos alguma Collection não tipada o compilador emite um
warning, podemos eliminar esse warning com uma annotation, isso existe no AspectJ
também, pois é possível que o compilador AspectJ não consiga estabelecer nenhum
join point para seu pointcut então, para evitar warnings podemos utilizar a annotation
@SuppressAjWarnings.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Nome qualificado: Neste caso, podemos capturar todos os elementos que contenham
determinada annotation. EX: @Gravavel ou @com.targettrust.aop.Curso ou !@Gravavel
O Mecanismo de join points com annotation é bastante fexível, abaixo temos algumas
das possíveis combinações para criarmos expressões de pointcuts utilizando
annotations. Os exemplos a seguir se aplicam a call() e execution().
Os recursos de match de join point com annotation em AspectJ são muito maleáveis
(como demostrado na tabela acima), agora será exemplificado o uso dessas
annotations em atributos e construtores.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Poderíamos ainda utilizar mais operadores lógicos como || ou &&, ainda seria possível
elaborar expressões mais complexas, quando fazemos um pointcut para construtor
utilizamos a propriedade initialization, mas podemos usar outras propriedades juntas a
esta.
Para fazer as expressões sobre atributos, usamos o padrão Java Bean e os métodos
getters/setters. Veja abaixo um exemplo de como utilizar esse recurso com annotations.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
@this/this: Este recurso faz o match apartir do objeto que foi interceptado, com
isso podemos especificar sub-clausulas nas expressões de join points. Ex.:
@this(Persistivel) && within(br.com) esse exemplo pega todos os objetos do pacote
br.com que tenham a annotations @Persistivel.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
@annotation: Esse é um recurso bastante avançado nas expressões de pointcuts
do AspectJ 1.5.X, com esse recurso podemos capturar annotations que tenham uma
política de retenção forte, ou seja, política de retenção em runtime. Ex: call (* * (..)) &&
@annotation(Forte) captura qualquer chamada de método em que o interceptado
tenha a annotation @Forte e essa anotação tenha política de retenção em runtime.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
É possivel gerar warnings e até mesmo erros com aspectos, isso se torna muito
interessante por exemplo para evitar que desenvolvedores acessem métodos
@Deprecated. Esse recurso pode ser utilizado para o reforço de contratos e até mesmo
para evitar o acoplamentos de código.
package br.com.targettrust.aop.pointcuts.annotation.erroswarnings;
declare warning :
within(br.com.targettrust.aop.pointcuts.annotation.erroswarnings.java.*)
&& call(* faz*(..))
: "Você não deve chamar metodos com o prefixo faz*";
declare error :
within(br.com.targettrust.aop.pointcuts.annotation.erroswarnings.java.*)
&& call(* deleteAll*(..))
: "Você não deve deletar tudo tche!!!";
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Injeção de Annotações
• Classes
• Métodos
• Construtores
• Atributos
package br.com.targettrust.aop.pointcuts.annotation.declareann;
import br.com.targettrust.aop.pointcuts.annotation.declareann.java.*;
declare @type :
br.com.targettrust.aop.pointcuts.annotation.declareann.java..* : @Exportavel;
declare @field : *
br.com.targettrust.aop.pointcuts.annotation.declareann.java..*.* : @Campo;
declare @constructor :
br.com.targettrust.aop.pointcuts.annotation.declareann.java.DeclareAnnTest3+.
new(..)
: @Novo;
}
Código 2.5 – Exemplos de utilização de injeção de annotations
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Exercícios
1) Faça um aspecto que intercepte toda criação de objetos que o construtor receba
uma String.
2) Faça um aspecto que intercepte toda execução de métodos que recebam um Map
como argumento.
3) Faça um aspecto que declare erros se o desenvolvedor instanciar algum objeto do
tipo ArrayList.
4) Faça um aspecto que injete annotations em objetos de pacotes dao.
5) Faça um aspecto que intercepte todas os getters que tenha a anotação @Serializavel
no target.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
3. Advice
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Objetivos
• Saber utilizar os tipos de Advices do AspectJ
• Conhecer recursos de ThisJoinPoint
• Saber criar aspectos
• Saber utilizar inner-type declarations
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Advices
• Before
• Around
• After
before(int x):
call (* *.*.exec*(int)) && args(x) {
System.out.println("[SimpleAdvice]modificado: " + (x+1));
}
}
No exemplo acima foi declarado um advice do tipo before(), e este advice irá
interceptar todos os métodos exec* de qualquer classe, de qualquer package. Esse
advice está capturando o parâmetro int do método exec*, este parâmetro é
referenciado pela variável x.
Esse advice não faz nada além de imprimir na tela o número do argumento, atribuindo
mais um.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Tipos de Advices
Before: Esse tipo de advice é executado antes da execução do pointcut. Supondo que
você declarou um pointcut que pega todas as execuções métodos que retornem um
double, com o advice before você tem o controle antes da execução do método. Esse
advice permite modificar os parâmetros do método, é ideal para fazer todo o tipo de
inicialização. Outra boa aplicação para este advice é para validações, podemos fazer
validações antes da execução de determinados métodos.
before():
call(* *.*save(Object)) {
System.out.println("Simples execucao antes do metodo.");
}
O Advice acima captura todas as execuções do método save que recebe um Object
como parâmetro. Foi utilizado pointcuts em linha por questões de facilidades. Esse
advice só imprime uma mensagem na tela.
Seria possível fazer validações neste advice e com isso poupar tempo dos
desenvolvedores e garantir que todos os acessos ao banco sejam menos custosos. Para
exemplificar isso o advice acima foi alterado, veja o resultado na figura abaixo.
before(Object x):
call(* *.*save(Object)) &&
args(x)
{
if (x==null)
throw new RuntimeException("Não pode salvar um objeto nulo!");
}
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
After: Este tipo de advice é executado depois da execução do pointcut. Supondo que
você declarou um pointcut que pega todas as execuções métodos que retornem um
double, com o advice after você tem o controle posterior à execução do método.
Esse tipo de advice permite modificar o retorno de um método. É útil para aplicar filtros
e adicionar informações a grafos de objetos. Este tipo de recurso pode ser utilizado
para realizações de bind dos mais diversos tipos, como por exemplos de-paras.
after():
call(* *.*save(Object)){
System.out.println("Simples execucao depois do metodo.");
}
}
Outra forma de usar o advice after é com o retituring que permite capturar o retorno
da execução de algum pointcut. Esse recurso pode ser usado de forma opcional. No
exemplo abaixo mostra como utilizar o recurso.
after()
returning(Object o):
call(public Object *.*.find()){
String x = (String)o;
x += "123";
System.out.println("retorno: " + x);
}
Este advice pega o retorno do método find, sendo que esse método retorna um objeto.
No advice foi feito um cast para String e adicionado o sufixo 123 na String original e
depois é impresso na tela.
O Advice after ainda possui o recurso de throwing que serve para capturarmos após o
levantamento de Exception. Veja abaixo um exemplo de uso desse recurso.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
O Advice do tipo after ainda possui mais uma forma, a throwing, com isso podemos
realizar operações após um método levantar uma determinada exception por exemplo.
Esse recurso faz com que o advice seja executado apenas se a Exception corretamente
definida na expressão pointcut for lançada. Veja a baixo um exemplo prático de como
usar o after throwing.
after()
throwing(Exception e):
call(public void *.*.delete()) {
System.out.println("Erro! Mensagem: " + e.getMessage());
}
Este recurso é muito bom para aplicar logs e todo o tipo de controles pós erro. Outra
aplicação seria na tolerância a falha, em um sistema assíncrono poderíamos disparar
um segundo processo caso determinado erro ocorra.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Around: Com certeza este é o tipo de advice mais poderoso e mais utilizado. Com esse
advice podemos interferir na execução do método de forma que possamos:
• Impedir a execução
• Modificar os parâmetros
• Modificar o retorno
• Levantar um Exception
• Engolir um Exception
Esse advice abre uma imensa gama de possibilidades. Quando utilizamos around é
necessário especificar uma sintaxe um pouco diferente dos outros advices, dentre as
diferenças existe o proceed(). Este método faz com que a execução do método
prossiga. Para o mesmo ocorrer é necessário informar os parâmetros do método,
podemos repassar os parâmetros originais, novos ou modificados.
int around():
call(public int *.*.soma(int,int)){
System.out.println("Around advice modificando valores constante 1");
return 1;
}
Como o advice around está definido como int isso torna obrigatório o retorno de um
inteiro. Esse retorno está hardcoded, mas poderia ser dinâmico. Veja no exemplo
abaixo como podemos fazer isso utilizando o proceed().
Neste exemplo foi utilizado o recurso args para recuperar os argumentos do método
soma2 e esse argumentos x,y foram referenciados dentro do advice around.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Quando declaramos exceptions checadas em advices elas devem ser declaradas com a
cláusula throws, e a mesma deve ser compatível com a do método original, caso ocorra
de modo contrário o compilador irá apresentar um erro.
E quanto a dois advices declarados no mesmo aspecto, o que for declarado primeiro
terá precedência sobre os outros.
Estas informações são importantes se você deseja aplicar algum mecanismo de proxy
como segurança, transação, autenticação, log. Pode ser necessário estabelecer uma
precedência entre os aspectos que aplicam os cross cuting concerns.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
ThisJoinPoint
package br.com.targettrust.aop.advice.thisJoinPoint.java;
O método execute não faz nada, mas está sendo invocado no método main.
package br.com.targettrust.aop.advice.thisJoinPoint;
O aspecto acima apenas imprime uma mensagem usando algumas informações que
existem no join point corrente. Veja o resultado da execução deste programa abaixo.
Executando: call(void
br.com.targettrust.aop.advice.thisJoinPoint.java.ThisJoinPointTest.execute())
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Método Descrição
Quando estamos em um advice do tipo after ou before e existe uma expressão call(), é
possível acessar informações do joint point passado quando ele existe, para isso
usamos a variável thisEnclosingJoinPointStaticPart.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Aspects
Aspectos são tipos de dados em AspectJ semelhantes a uma classe Java, os aspectos
são os meios que possibilitam a expressão de um crosscuting concern. É dentro dos
Aspectos que são declaradas as expressões pointcuts e os advices.
Aspectos podem extender outros aspectos, desde que abstratos, se um aspecto tenta
estender outro aspecto que não é abstrato causa um erro de compilação.
Por default os aspectos são singletons, significa que a mesma instância do aspecto será
para toda execução de um programa Java.
Obs.: A Classe utilitária org.aspectj.lang.Aspects não pode ser utilizada em uma classe
Java, pois isso quebra o conceito básico de AOP, os aspectos podem ver as classes Java,
entretanto as classes Java não vêem os aspectos. Se você fizer isso irá receber um erro
de compilação.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Veja abaixo um exemplo de como podemos utilizar aspectos abstratos e extensão de
aspectos com os recursos da classe utilitária Aspects.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.aspect.java;
class A{
public void func(){}
}
class B{
public void func(){}
}
Supondo que temos as três classes acima, a classe A e B com o método func() e uma
classe main com a instanciação e invocação dos métodos func() de A e B. Agora se
quiséssemos contrar quantas vezes o método func() foi chamado. poderíamos fazer um
aspecto conforme este abaixo:
package br.com.targettrust.aop.aspect;
package br.com.targettrust.aop.aspect;
import org.aspectj.lang.Aspects;
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Por default aspectos tem as mesmas regras de acesso e privilégios que o Java tem, mas
podemos modificar essas políticas tornando o aspecto privilegiado. Quando um
aspecto é privilegiado, o mesmo pode acessar variáveis protected e até mesmo
variáveis private. Porém esses recursos só são válidos para innertype declarations feitas
pelo mesmo aspecto ou por outros.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Inner-Type Declarations
Recurso do AspectJ que permite adicionar membros nas classes de forma dinâmica.
Com este recuroso podemos adicionar atributos a um classe Java e utilizar essa
informação para algum processamento em algum advice de um aspecto.
O código abaixo mostra como adicionar a Classe br.com.A como classe pai da classe
br.com.B.
No exemplo acima foi feito que a classe br.com.B implementase a interface br.com.A,
quando fazemos isso essas informações podem ser acessadas até mesmo por uma
classe Java através de cast para a interface ou com o uso de Reflection.
Para adicionar atributos a uma classe Java podemos fazer conforme o exemplo abaixo:
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
No exemplo acima está sendo adicionda uma List<Porta> no objeto casa. Perceba que
o atributo está sendo adicionado de forma privada, isso significa que não poderá ser
acessada de fora da classe a não ser que o aspecto seja privilegiado.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Para adicionar métodos a uma classe ( Isso é necessário quando implementamos uma
interface via aspectos) podemos fazer conforme o exemplo abaixo.
No código acima foi adicionado o método pintar ao objeto Casa, esse método tem
como parâmetro um objeto Cor, esse método pode ser acessível normalmente se ele
estiver em uma interface ou via Reflection. Dentro de um advice ou de um outro
aspecto isto pode ser acessado de forma natural pois o método será público.
Outro recurso que podemos utilizar é a adição de contrutores a classes Java através de
inner-type declarations, confira o exemplo abaixo.
No exemplo acima foi adicionado um construtor ao objeto Casa, esse objeto agora tem
um construtor que recebe um String contendo a rua. A chamada super() é opcional,
mas o compilador AspectJ irá lançar um warning se você não a colocar. Por questões de
boas práticas de programação recomenda-se utilizar.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Exercícios
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
4. Recursos Adicionais
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Objetivos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Um ponto importante que deve ser lembrado quando optamos por uma abordagem
dirigida a anotações, é que quando utilizamos aspectos com anotações não é possivel
declarar aspectos privilegiados.
Quando utilizamos o @Pointcut para declarar o pointcut existem algumas regras, tais
como: o método deve retornar void, não deve ter nada no seu corpo (exeto o caso if
que será abordado mais tarde). Para declarar um pointcut abstrato basta fazer com que
o método seja abstrato. Ao fazer desta maneira pode parecer um pouco estranha a
forma de uso, e é mesmo bastante incomun. O que se pode fazer é utilizar expressões
pointcuts direto em anotações advice, isso faz com que o código fique mais natural.
Se você utilizar algum recurso do tipo: args(), target(), this(), @args(), @this(),
@annotation, o parâmetro em questão deverá aparcer na assinatura do método que
contém a annotation @Pointcut.
Para o uso do recurso if() o método deve ser public static boolean como no exemplo
abaixo.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
O exemplo acima define um pointcut que captura todas as chamadas de métodos que
recebam um inteiro e este inteiro seja maior que zero. Esse código acima tem
equivalência ao seguinte código AspectJ:
pointcut chamadaIf(int i) : call(* *.*(int)) && args(i) && if(i > 0);
Para capturar o joint point corrente para algum processamento, basta declarar o
org.aspectj.lang.JoinPoint no Pointcut e depois no Advice e pronto! O mecanismo de
annotations irá prover a instância desse objeto.
Para utilizarmos as anotações destinadas a advices o método Java deve retornar void e
ser público, porém no caso do advice around, o advice deve retornar o tipo de dado
conforme a especificação do pointcut do advice around.
@AfterReturning("criticalOperation()")
public void phew() {
System.out.println("phew");
}
@AfterReturning(pointcut="call(Foo+.new(..))",returning="f")
public void itsAFoo(Foo f) {
System.out.println("It's a Foo: " + f);
}
No exemplo acima estamos capturando todas as instâncias das classes Foo ou filhas
dele e pegando o retorno em f que é utilizando no advice.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Com o advice do tipo @Around existe o problema do proceed() que não pode ser
chamado no meio do código Java, se não você terá um erro de compilação, para
manter um bom design e a compatibilidade de compilação do mecanismo de
annotações do
Java 5.0 devemos utilziar a interface org.aspectj.lang.ProceedingJoinPoint que será um
dos parâmetros do método com a anotação @Around.
@Around("call(* *.*.now(..))")
public String getData(ProceedingJoinPoint pjp){
try {
System.out.println(pjp.getSignature());
return (String)pjp.proceed();
}catch (Throwable e) {
return null;
No exemplo acima fica bem claro que utilizar esse recurso é simples, e na instância de
ProceedingJoinPoint ainda contamos com recursos do JoinPoint, como por exemplo a
assinatura do pointcut().
Inner-type declarations
Para respeitar os padrões do Java 5.0, quando usamos inner-type declarations através
de anotações não temos disponíveis os recursos de adição de campos e construtores.
Isso ocorre porque o compilador javac não tem os recursos que o compilador AspectJ
possui.
Somente os recursos de adição de interfaces estão disponíveis, com uma sutil diferença
é possivel utilizar esses recursos. Veja o exemplo abaixo.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.annotation.innertype.clazz;
Como você pode perceber é uma classe Java comum. É uma calculadora muito simples
com apenas as operações básicas de soma, subtração, divisão e multiplicação. Para esse
exemplo será adicionada a operação de potenciação a essa calculadora através do
recurso de inner-type com anotações. Só podemos utilizar esse recurso associado a
uma interface.
package br.com.targettrust.aop.annotation.innertype;
A Interface acima define como a operação de potência deve ser. Agora vamos a
implementação padrão dessa operação com o código abaixo.
package br.com.targettrust.aop.annotation.innertype;
public PotenciaImpl() { }
Veja no Aspecto seguinte como fazer a classe SimpleCacl ter os recursos da Potencia.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.annotation.innertype;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class AnnotationInnerTypeAspect {
@DeclareParents(
value="br.com.targettrust.aop.annotation.innertype.clazz.*",
defaultImpl=PotenciaImpl.class)
public Potencia implementadores;
package br.com.targettrust.aop.annotation.innertype.java;
import br.com.targettrust.aop.annotation.innertype.Potencia;
import br.com.targettrust.aop.annotation.innertype.clazz.SimpleCalc;
@SuppressWarnings("unchecked")
public static void main(String[] args) {
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Implementa: interface
br.com.targettrust.aop.annotation.innertype.Potencia
Potencia de 5 = 25
Código 4.11 – Resultado da execução da classe AnnotationInnerTypeAspectTest
Como você pode perceber a classe de fato implementa a interface que injetamos via
AspectJ, e foi feito o cast de maneira natual para a interface Potencia. Após o cast foi
invocado o método pow(5) e obtivemos o resultado correto da execução.
@DeclareWarning("call(java.util.Date.new(..))")
static final String message = "Você não deve utilizar java.util.Date.
Utilize Joda-Time!";
Código 4.12 – Exemplo de uso de declare warning com anotações.
Nessa anotação você deve informar uma expressão pointcut que será responsável por
determinar quais serão os alvos de seu warning. Essa anotação deve se utilizada em
cima de um atributo do tipo String que deve ser obrigatoriamente final, por questões
de boas praticas você pode colocar static também.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
determinar quais classes ficaram com erros. Claro que também é necessário um String
do tipo final para ser a mensagem de erro.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Declare Soft
Esse recurso foi introduzido apartir do AspectJ 1.5.X. É um recurso muito importante
com ele podemos fazer com que as Exceptions do Java sejam encapsuladas em uma
Exception do AspectJ que é do tipo unchecked e por consequência estende
RuntimeException. Se a exceção que for utilizada para o soft for uma Exception que
estende RuntimeException você receberá um warning e o soft não irá ocorrer.
package br.com.targettrust.aop.declaresoft;
package br.com.targettrust.aop.declaresoft;
No aspecto acima foi informado em qual Exception deveria ser feito o soft e qual
expressão pointcut deveria ser aplicado. Assim podemos limitar o soft somente para
alguns métodos.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.declaresoft.java;
import org.aspectj.lang.SoftException;
import br.com.targettrust.aop.declaresoft.MinhaExcpetionChata;
Essa classe de testes chama o metodo fazAlgo() que retorna um Exception do tipo
MinhaExceptionChata essa exception vai sofrer o soft. Podemos observar que isso
ocorre pelo seguinte bloco de try/cacth neste bloco está sendo tratada uma exception
do Java e a SoftException do AspectJ. Veja o resultado da execução desse código
abaixo.
1 - SoftExcetion:
br.com.targettrust.aop.declaresoft.MinhaExcpetionChata: Exception
chata mesmo
Código 4.16 – Resultado da execução da classe DeclareSodtTest.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.dbc;
import java.math.BigDecimal;
Podemos resolver estes problemas em tempo de design? Sim, com DBC podemos fazer
isto. Para isto, usaremos os conceitos de pré-condições, pós-condições e invariantes.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
DBC é um conceito em tem diversas implementações em muitas linguagens como C,
Java, .NET , Ruby, etc. Podemos fazer uso fruto dos conceitos de DBC com o próprio
AspectJ, porém não temos recursos prontos na linguagem para isso. O recomendo é
um framework de DBC para Java, existem muitos dentre eles o JContract, C4J,
Contract4J que utiliza o AspectJ como base.
Pré-Condições:
Pós-Condições:
Invariantes:
Para atender esse contrato estabelecido através das premissas do DBC veja a classe
Java abaixo.
package br.com.targettrust.aop.dbc;
import java.math.BigDecimal;
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Pela implementação da classe Java podemos ver que não foi implementado nenhum
tipo de validação para atender o contrato DBC que foi estipulado previamente.
Provavelmente se esta classe fosse executada do jeito que ela se encontra, teríamos
sérios problemas. Agora vamos ver o aspecto que terá a implementação DBC.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
package br.com.targettrust.aop.dbc;
import java.math.BigDecimal;
private
pointcut debitarPointcut(BigDecimal b):
execution(public BigDecimal *.debitar(BigDecimal)) &&
args(b) &&
within(br.com.targettrust.aop.dbc.*);
after(ContaCorrente cc):
execution(public BigDecimal *.debitar(BigDecimal)) &&
target(cc) &&
within(br.com.targettrust.aop.dbc.*)
{
BigDecimal saldo = cc.consultaSaldo();
if (cc.consultaSaldo().doubleValue()<=0){
cc.creditar(new BigDecimal(5d).subtract(saldo));
throw new
RuntimeException("Erro a contacorrente não pode ter saldo"
+"negativo! Valor: " + saldo.doubleValue());
}
if (cc.consultaSaldo().doubleValue()<=4){
cc.creditar(new BigDecimal(5d).subtract(saldo));
throw new
RuntimeException("Erro a contacorrente não pode ter saldo"
+ "menor que 5 reais! Valor: " + saldo.doubleValue());
}
}
}
Nesta implementação não há nehum recurso que não tenha sido discutido nesta
apostila, ela utiliza os recursos que você já deve estar familiarizado agora. Porém, aqui
estão inseridos os conceitos de DBC que expressam pelas pré-condições, pós-
condições e invariantes.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Veja um código Java para testar esses recursos em ação.
package br.com.targettrust.aop.dbc.java;
import java.math.BigDecimal;
import br.com.targettrust.aop.dbc.ContaCorrenteImpl;
import br.com.targettrust.aop.dbc.ContaCorrente;
try{
cc.debitar(new BigDecimal("-1"));
}catch(Exception e){
System.out.println(e.getMessage());
}
try{
cc.debitar(new BigDecimal("1001"));
}catch(Exception e){
System.out.println(e.getMessage());
}
try{
cc.debitar(new BigDecimal("2"));
}catch(Exception e){
System.out.println(e.getMessage());
System.out.println("Saldo atual: " +
cc.consultaSaldo());
}
try{
cc.debitar(new BigDecimal("200"));
}catch(Exception e){
System.out.println(e.getMessage());
System.out.println("Saldo atual: " +
cc.consultaSaldo());
}
}
Código 4.20 – Classe Java para testes.
Nessa classe foi forçado todos os tipos de situações que iriam estourar algum tipo de
erro. Ao executar essa classe nós teremos o seguinte resultado.
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
Exercícios
1) Faça um aspecto utilizando anotações que faça tracing. Este aspecto deve
mostrar todos os parâmetros do método e o seu retorno também. Chame o
método execute (String proc, Object inst) várias vezes em uma classe de testes.
2) Declare um erro utilizando anotações para quando for utilizando a classe
java.util.HashMap() em uma classe TesteMapEx02 com os métodos usaMap() e
testaMap().
3) Baseado no exercicio anterior, faça o mesmo, só que agora gere um warning,
utilizando anotações também.
4) Utilizando os conceitos de DBC faça um aspecto que valide as seguintes
premissas:
1 Pré condições:
1. O hotel não aceita hospedes de cabelo verde.
2. O hotel não aceita chekin antes das 10:00hs.
2 Pós condições:
1. Ao sair do hotel deve-se pagar a conta.
2. Ao sair do hotel deve-se deixar 20% de gorjeta.
3 Invariantes:
1. Para alugar o quarto a pessoa deve ter, no mínimo R$
500,00.
Para esse execício implemente a interface Hotel que segue:
Package br.com.targettrust.aop.advice.after.java;
import java.math.BigDecimal;
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM
AOP – AspectJ 1.5.4 – Programação Orientada a Aspectos
HTTP://DIEGO-PACHECO.BLOGSPOT.COM