Introduction to Pointcut Expressions in Spring – Spring中的指向性表达式介绍

最后修改: 2015年 12月 16日

1. Overview

1.概述

In this tutorial, we’ll discuss the Spring AOP pointcut expression language.

在本教程中,我们将讨论Spring AOP点式表达语言。

First, we’ll introduce some terminology used in aspect-oriented programming. A join point is a step of the program execution, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution. A pointcut is a predicate that matches the join points, and the pointcut expression language is a way of describing pointcuts programmatically.

首先,我们来介绍一下面向方面编程中的一些术语。一个连接点是程序执行的一个步骤,例如一个方法的执行或一个异常的处理。在Spring AOP中,一个连接点总是代表一个方法的执行。pointcut是与连接点相匹配的谓词,pointcut表达式语言是以编程方式描述pointcuts的方法。

2. Usage

2.使用方法

A pointcut expression can appear as a value of the @Pointcut annotation:

一个pointcut表达式可以作为@Pointcut注解的一个值出现。

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

The method declaration is called the pointcut signature. It provides a name that advice annotations can use to refer to that pointcut:

该方法声明被称为pointcut签名。它提供了一个名称,建议注解可以用来引用该切点。

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

A pointcut expression can also appear as the value of the expression property of an aop:pointcut tag:

一个pointcut表达式也可以作为expression属性的值出现在aop:pointcut标签上。

<aop:config>
    <aop:pointcut id="anyDaoMethod" 
      expression="@target(org.springframework.stereotype.Repository)"/>
</aop:config>

3. Pointcut Designators

3.指向性符号

A pointcut expression starts with a pointcut designator (PCD), which is a keyword telling Spring AOP what to match. There are several pointcut designators, such as the execution of a method, type, method arguments, or annotations.

一个切点表达式以切点指定器(PCD)开始,这是一个告诉Spring AOP要匹配什么的关键字。有几个点切代号,例如方法的执行、类型、方法参数或注释。

3.1. execution

3.1.执行

The primary Spring PCD is execution, which matches method execution join points:

Spring的主要PCD是execution,它与方法的执行连接点相匹配。

@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))")

This example pointcut will exactly match the execution of the findById method of the FooDao class. This works, but it’s not very flexible. Suppose we’d like to match all the methods of the FooDao class, which may have different signatures, return types, and arguments. To achieve this, we can use wildcards:

这个例子中的切点将与FooDao类的findById方法的执行完全一致。这很有效,但是它不是很灵活。假设我们想匹配FooDao类的所有方法,它们可能有不同的签名、返回类型和参数。为了达到这个目的,我们可以使用通配符。

@Pointcut("execution(* com.baeldung.pointcutadvice.dao.FooDao.*(..))")

Here, the first wildcard matches any return value, the second matches any method name, and the (..) pattern matches any number of parameters (zero or more).

这里,第一个通配符匹配任何返回值,第二个匹配任何方法名称,而(..)模式匹配任何数量的参数(零或更多)。

3.2. within

3.2.

Another way to achieve the same result as the previous section is by using the within PCD, which limits matching to join points of certain types:

实现与上一节相同结果的另一种方法是使用within PCD,它将匹配限制在某些类型的连接点。

@Pointcut("within(com.baeldung.pointcutadvice.dao.FooDao)")

We can also match any type within the com.baeldung package or a sub-package:

我们也可以匹配com.baeldung包或子包中的任何类型。

@Pointcut("within(com.baeldung..*)")

3.3. this and target

3.3.thistarget

this limits matching to join points where the bean reference is an instance of the given type, while target limits matching to join points where the target object is an instance of the given type. The former works when Spring AOP creates a CGLIB-based proxy, and the latter is used when a JDK-based proxy is created. Suppose that the target class implements an interface:

this将匹配限制在bean引用是给定类型的实例的连接点上,而target将匹配限制在目标对象是给定类型的实例的连接点上。前者在Spring AOP创建基于CGLIB的代理时起作用,而后者则在创建基于JDK的代理时使用。假设目标类实现了一个接口。

public class FooDao implements BarDao {
    ...
}

In this case, Spring AOP will use the JDK-based proxy, and we should use the target PCD because the proxied object will be an instance of the Proxy class and implement the BarDao interface:

在这种情况下,Spring AOP将使用基于JDK的代理,我们应该使用target PCD,因为被代理的对象将是Proxy类的实例并实现BarDao接口。

@Pointcut("target(com.baeldung.pointcutadvice.dao.BarDao)")

On the other hand, if FooDao doesn’t implement any interface, or the proxyTargetClass property is set to true, then the proxied object will be a subclass of FooDao and we can use the this PCD:

另一方面,如果FooDao没有实现任何接口,或者proxyTargetClass属性被设置为true,那么被代理的对象将是FooDao的一个子类,我们可以使用thisPCD。

@Pointcut("this(com.baeldung.pointcutadvice.dao.FooDao)")

3.4. args

3.4.args

We can use this PCD for matching particular method arguments:

我们可以使用这个PCD来匹配特定的方法参数。

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

This pointcut matches any method that starts with find and has only one parameter of type Long. If we want to match a method with any number of parameters, but still having the fist parameter of type Long, we can use the following expression:

这个快捷键可以匹配任何以find开头的方法,并且只有一个Long类型的参数。如果我们想匹配一个具有任何数量参数的方法,但仍然具有Long类型的第一个参数,我们可以使用以下表达式。

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

3.5. @target

3.5.@target

The @target PCD (not to be confused with the target PCD described above) limits matching to join points where the class of the executing object has an annotation of the given type:

@target PCD(不要与上面描述的target PCD混淆)将匹配限制在执行对象的类具有给定类型的注释的连接点。

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

3.6. @args

3.6.@args

This PCD limits matching to join points where the runtime type of the actual arguments passed have annotations of the given type(s). Suppose that we want to trace all the methods accepting beans annotated with the @Entity annotation:

这个PCD将匹配限制在实际传递的参数的运行时类型具有给定类型注释的连接点上。假设我们想追踪所有接受带有@Entity注解的bean的方法。

@Pointcut("@args(com.baeldung.pointcutadvice.annotations.Entity)")
public void methodsAcceptingEntities() {}

To access the argument, we should provide a JoinPoint argument to the advice:

为了访问该参数,我们应该向建议提供一个JoinPoint参数。

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

3.7. @within

3.7.@within

This PCD limits matching to join points within types that have the given annotation:

这个PCD将匹配限制在具有给定注释的类型中的连接点。

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

Which is equivalent to:

这相当于。

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

3.8. @annotation

3.8.@annotation

This PCD limits matching to join points where the subject of the join point has the given annotation. For example, we can create a @Loggable annotation:

这个PCD将匹配限制在连接点的主体具有给定注释的连接点上。例如,我们可以创建一个@Loggable注释。

@Pointcut("@annotation(com.baeldung.pointcutadvice.annotations.Loggable)")
public void loggableMethods() {}

Then we can log the execution of the methods marked by that annotation:

然后我们可以记录该注解所标记的方法的执行情况。

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

4. Combining Pointcut Expressions

4.组合指向性表达式

Pointcut expressions can be combined using &&, ||, and ! operators:

可以使用&&||!操作符来组合指向性表达。

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

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

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

5. Conclusion

5.结论

In this brief article about Spring AOP and poincuts, we illustrated some examples of pointcut expressions.

在这篇关于Spring AOP和poincuts的简短文章中,我们说明了一些pointcut表达式的例子。

The full set of examples can be found over on GitHub.

完整的例子可以在GitHub上找到over