• Nenhum resultado encontrado

A sintaxe AspectJ de declaração de point cuts

No documento Casa do Código. Prefácio (páginas 123-128)

}

Fica claro que é basicamente a mesma implementação do nosso profilador. A diferença está no fato de incluirmos duas novas anotações.@Aspect, como o próprio nome diz, identifica um bean como um aspecto. Já a anotação@Aroundidentifica que o métodoprofilar- que obrigatoriamente deve receber um parâmetro do tipo

ProceedingJoinPoint- é um advice do tipo around.

O mais interessante do uso das anotações é que podemos ter mais de um advice do mesmo tipo - around - implementado em uma mesma classe: basta incluir mais anotações@Aroundem seu corpo. O leitor deve estar curioso a respeito do significado do parâmetro que passei para esta anotação, certo?

5.12

A sintaxe AspectJ de declaração de point cuts

Como mencionado, uma das maiores vantagens do AspectJ é a sua sintaxe para defi- nição de point cuts. Como visto em nosso último aspecto, a anotação@Aroundrecebe como parâmetro uma expressão. O assunto desta seção será justamente entender o que esta significa.

Caso você já tenha trabalhado com AspectJ, é importante mencionar que, como o Spring não oferece suporte a 100% deste framework, e também pelo fato de nossa AOP ser completamente baseada em proxies, não há suporte nativo para todas as possibilidades que esta linguagem para definição de point cuts nos oferece, o que não é em si uma grande desvantagem, visto que o suportado dará conta da esmagadora maioria das situações encontradas no desenvolvimento de aplicações corporativas.

A sintaxe aplicada é razoavelmente simples e a imagem abaixo nos ajudará a entendê-la melhor:

Figura 5.4: Definindo um point cut

O primeiro elemento sempre é o gatilho responsável por disparar o aspecto. Na esmagadora maioria das vezes este será do tipoexecutionque, como o próprio nome já diz, identifica a execução do método alvo. Por esta razão neste capítulo daremos muito mais atenção a este tipo.

Tipos de gatilho mais comuns

• execution(): identifica a execução do método alvo.

• within(): define um join point dentro de um conjunto de tipos. • this(): o aspecto será aplicado a objetos do tipo do bean decla-

rado.

• annotation(): identifica join points de acordo com as anotações passadas como parâmetro.

• args: identifica join points que recebam determinada lista de pa- râmetros.

O gatilhoexecutionrecebe como parâmetro a especificação do método alvo, que é composta por quatro componentes. O primeiro diz respeito ao tipo de retorno

5.12. A sintaxe AspectJ de declaração de point cuts Casa do Código esperado, seguido do caminho completo até a classe, nome do método e, finalmente, quais os parâmetros que este receberá.

É importante mencionar que podemos usar caracteres coringa na declaração do nome da classe e método alvo, tal como podemos ver nos exemplos:

/*

O método pode retornar qualquer valor. A classe pode estar em qualquer pacote, porém deve se chamar 'DAOPessoas'.

O método pode possuir qualquer nome, o que indica que pegaremos todos os métodos, ignorando os parâmetros que estes possam receber. */

execution(* *.DAOPessoas.*(..))

/*

Todas as classes cujo nome comece com 'DAO', levando em consideração apenas os métodos chamados 'ler' ignorando os parâmetros recebidos e o tipo de retorno

*/

execution(* *.DAO*.ler(..))

/*

Todos os métodos do tipo void de qualquer classe do pacote casadocodigo ignorando os parâmetros

*/

execution(void casadocodigo.*(..))

/*

Todos os métodos que recebam como parâmetro um objeto do tipo File pertencentes ao pacote casadocodigo

*/

execution(* casadocodigo.*(java.io.File))

/*

Execução de qualquer método público de qualquer bean */

Outro gatilho interessante é o @annotation, que nos permite criar join points para todas as classes que possuam determinada anotação. O exemplo abaixo leva em consideração todas as classes que possuam a anotação@Componentdo Spring.

@annotation(org.springframework.stereotype.Component)

O Spring também estende o conjunto de gatilhos com o tipobean, que nos per- mite referenciar um bean por um nome específico ou usando caracteres coringa como nos exemplos abaixo:

/* Aponta para ao bean daoPessoas */

bean("daoPessoas")

/* Aponta para qualquer bean cujo nome comece com 'dao' */

bean("dao*")

É interessante mencionar que também podemos aplicar expressões lógicas na definição de nossos point cuts.

Escrevendo outros tipos de advices

Tirando proveito das anotações, podemos ver como implementar mais de um tipo de advice em uma mesma classe, como no código a seguir:

@Aspect @Component

public class AdviceAroundProfiladorAnotacoes {

private List<Long> tempos = new ArrayList<Long>();

public List<Long> getTempos() {

return tempos; }

// Nosso advice do tipo around

@Around("execution(* casadocodigo.DAOPessoas.*(..))")

public Object profilar(ProceedingJoinPoint joinPoint)

throws Throwable {

long momentoInicial = System.currentTimeMillis(); Object resultado = joinPoint.proceed();

5.12. A sintaxe AspectJ de declaração de point cuts Casa do Código tempos.add(tempo);

System.out.println("Tempo para executar = " + tempo + "ms");

return resultado; }

// Mais de um advice pode ser declarado na mesma classe // quando usamos anotações

}

Os parâmetros passados aos advices de tipobeforeouafter throwingsão op- cionais. Para advices do tipo before, como podemos ver a seguir, é possível pas- sar informações a respeito do join point definindo um parâmetro de entrada do tipoorg.aspectj.lang.JoinPoint, que nos permite, como pôde ser visto anteri- ormente, interceptar os parâmetros que serão passados ao método alvo.

@Aspect @Component

public class AdviceAroundProfiladorAnotacoes { // acima está o nosso advice do tipo around // Advice do tipo before

@Before("execution(* casadocodigo.DAOPessoas.persistir(..))")

public void coletarEstatisticas(JoinPoint joinPoint) { File arquivo = (File) joinPoint.getArgs()[1]; obterEstatisticasArquivo(arquivo)

}

// restante da classe abaixo }

No caso de um advice do tipo after throwing, é importante uma nota adicional: caso seja passado um parâmetro para este que corresponda à exceção disparada, na anotação@AfterThrowingque vemos a seguir deve ser incluído o atributo adicional throwing, cujo valor corresponde ao nome do parâmetro declarado no método que implementa o advice.

@Aspect @Component

public class AdviceAroundProfiladorAnotacoes {

// para facilitar a leitura // Advice do tipo after throwing

@AfterThrowing(

pointcut="execution(* casadocodigo.DAOPessoas.*(..))", throwing="ex")

public void informar(IOException ex) { enviarEmail(ex)

}

// restante da classe ignorado para facilitar leitura }

No documento Casa do Código. Prefácio (páginas 123-128)