Introdução às expressões pointcut na primavera

Introdução às expressões pointcut na primavera

1. Visão geral

Neste tutorial, discutiremos a linguagem de expressões de corte de pontos do Spring AOP.

Introduziremos primeiro uma terminologia usada na programação orientada a aspectos. Umjoin point é uma etapa da execução do programa, como a execução de um método ou o tratamento de uma exceção. No Spring AOP, um ponto de junção sempre representa uma execução de método. Umpointcut é um predicado que corresponde aos pontos de junção e umpointcut expression language é uma maneira de descrever os pontos de corte de forma programática.

2. Uso

Uma expressão de pointcut pode aparecer como um valor da anotação@Pointcut:

@Pointcut("within(@org.springframework.stereotype.Repository *)")
public void repositoryClassMethods() {}

A declaração do método é chamada depointcut signature. Ele fornece um nome que pode ser usado por anotações de conselhos para se referir a esse apontamento.

@Around("repositoryClassMethods()")
public Object measureMethodExecutionTime(ProceedingJoinPoint pjp) throws Throwable {
    ...
}

Uma expressão de pointcut também pode aparecer como o valor da propriedadeexpression de uma tagaop:pointcut:


    

3. Pointcut Designators

Uma expressão de pointcut começa compointcut designator (PCD), que é uma palavra-chave dizendo ao Spring AOP o que corresponder. Existem vários designadores de ponto de corte, como a execução de um método, um tipo, argumentos de método ou anotações.

3.1 execution

O Spring PCD primário éexecution, que corresponde aos pontos de junção de execução do método.

@Pointcut("execution(public String org.example.dao.FooDao.findById(Long))")

Este pointcut de exemplo corresponderá exatamente à execução do métodofindById da classeFooDao. Isso funciona, mas não é muito flexível. Suponha que gostaríamos de combinar todos os métodos da classeFooDao, que podem ter assinaturas, tipos de retorno e argumentos diferentes. Para conseguir isso, podemos usar curingas:

@Pointcut("execution(* org.example.dao.FooDao.*(..))")

Aqui, o primeiro curinga corresponde a qualquer valor de retorno, o segundo corresponde a qualquer nome de método e o padrão(..) corresponde a qualquer número de parâmetros (zero ou mais).

3.2 within

Outra maneira de obter o mesmo resultado da seção anterior é usando owithin PCD, que limita a correspondência para pontos de junção de certos tipos.

@Pointcut("within(org.example.dao.FooDao)")

Também podemos combinar qualquer tipo no pacoteorg.example ou em um subpacote.

@Pointcut("within(org.example..*)")

3.3 this and target

this limita a correspondência para pontos de junção onde a referência do bean é uma instância do tipo fornecido, enquantotarget limita a correspondência para pontos de junção onde o objeto de destino é uma instância do tipo dado. O primeiro funciona quando o Spring AOP cria um proxy baseado em CGLIB e o último é usado quando um proxy baseado em JDK é criado. Suponha que a classe de destino implemente uma interface:

public class FooDao implements BarDao {
    ...
}

Nesse caso, Spring AOP usará o proxy baseado em JDK e você deve usar otarget PCD porque o objeto com proxy será uma instância da classeProxy e implementará a interfaceBarDao:

@Pointcut("target(org.example.dao.BarDao)")

Por outro lado, seFooDao não implementar nenhuma interface ou a propriedadeproxyTargetClass for definida como verdadeira, o objeto proxy será uma subclasse deFooDaoe o PCDthis poderia ser usado:

@Pointcut("this(org.example.dao.FooDao)")

3.4 args

Este PCD é usado para corresponder argumentos de métodos específicos:

@Pointcut("execution(* *..find*(Long))")

Este pointcut corresponde a qualquer método que comece com find e tenha apenas um parâmetro do tipoLong. Se quisermos combinar um método com qualquer número de parâmetros, mas tendo o primeiro parâmetro do tipoLong, poderíamos usar a seguinte expressão:

@Pointcut("execution(* *..find*(Long,..))")

3.5 @target

O@target PCD (não deve ser confundido com otarget PCD descrito acima) limita a correspondência para pontos de junção onde a classe do objeto em execução tem uma anotação do tipo dado:

@Pointcut("@target(org.springframework.stereotype.Repository)")

3.6 @args

Esse PCD limita a correspondência aos pontos de junção nos quais o tipo de tempo de execução dos argumentos reais passados ​​possui anotações do (s) tipo (s) fornecido (s). Suponha que desejamos rastrear todos os métodos que aceitam beans anotados com a anotação@Entity:

@Pointcut("@args(org.example.aop.annotations.Entity)")
public void methodsAcceptingEntities() {}

Para acessar o argumento, devemos fornecer um argumentoJoinPoint para o conselho:

@Before("methodsAcceptingEntities()")
public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {
    logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]);
}

3.7 @within

Esse PCD limita a correspondência aos pontos de junção em tipos com a anotação fornecida:

@Pointcut("@within(org.springframework.stereotype.Repository)")

O que equivale a:

@Pointcut("within(@org.springframework.stereotype.Repository *)")

3.8 @annotation

Esse PCD limita a correspondência aos pontos de junção em que o assunto do ponto de junção possui a anotação fornecida. Por exemplo, podemos criar uma anotação@Loggable:

@Pointcut("@annotation(org.example.aop.annotations.Loggable)")
public void loggableMethods() {}

Então, podemos registrar a execução dos métodos marcados por essa anotação:

@Before("loggableMethods()")
public void logMethod(JoinPoint jp) {
    String methodName = jp.getSignature().getName();
    logger.info("Executing method: " + methodName);
}

4. Combinando Expressões de Pointcut

Expressões de ponto de corte podem ser combinadas usando os operadores&&,||e!:

@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}

@Pointcut("execution(* *..create*(Long,..))")
public void firstLongParamMethods() {}

@Pointcut("repositoryMethods() && firstLongParamMethods()")
public void entityCreationMethods() {}

5. Conclusão

Nesta introdução rápida ao Spring AOP e pointcuts, ilustramos alguns exemplos do uso de expressões pointcut.

O conjunto completo de exemplos pode ser encontrado emmy github project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.