Declaring Advice
通知与切点表达式关联,并在与切点匹配的方法执行之前、之后或前后运行。切点表达式可以是 inline pointcut,也可以是对 named pointcut 的引用。
Advice is associated with a pointcut expression and runs before, after, or around method executions matched by the pointcut. The pointcut expression may be either an inline pointcut or a reference to a named pointcut.
Before Advice
您可以使用 @Before
批注在方面中声明之前的建议。
You can declare before advice in an aspect by using the @Before
annotation.
以下示例使用内嵌切入点表达式。
The following example uses an inline pointcut expression.
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@Aspect
class BeforeExample {
@Before("execution(* com.xyz.dao.*.*(..))")
fun doAccessCheck() {
// ...
}
}
如果我们使用 named pointcut,我们可以按如下方式重写前一个示例:
If we use a named pointcut, we can rewrite the preceding example as follows:
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.CommonPointcuts.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@Aspect
class BeforeExample {
@Before("com.xyz.CommonPointcuts.dataAccessOperation()")
fun doAccessCheck() {
// ...
}
}
After Returning Advice
当匹配方法执行正常返回时,返回通知运行。你可以通过使用 @AfterReturning
注释声明它。
After returning advice runs when a matched method execution returns normally.
You can declare it by using the @AfterReturning
annotation.
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("execution(* com.xyz.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
@AfterReturning("execution(* com.xyz.dao.*.*(..))")
fun doAccessCheck() {
// ...
}
}
您可以有多个advice声明(以及其他成员),全部在同一个aspect中。我们在这些示例中仅显示一个advice声明,以重点关注每个advice的效果。 |
You can have multiple advice declarations (and other members as well), all inside the same aspect. We show only a single advice declaration in these examples to focus the effect of each one. |
有时,你需要在通知正文中访问实际的返回值。你可以使用 @AfterReturning
的形式将返回值与 getthataccess 绑定,如下面的示例所示:
Sometimes, you need access in the advice body to the actual value that was returned.
You can use the form of @AfterReturning
that binds the return value to get that
access, as the following example shows:
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="execution(* com.xyz.dao.*.*(..))",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
@AfterReturning(
pointcut = "execution(* com.xyz.dao.*.*(..))",
returning = "retVal")
fun doAccessCheck(retVal: Any?) {
// ...
}
}
returning
特性中的名称必须与通知方法中的参数名称对应。当方法执行返回时,返回值作为相应的参数值传递给通知方法。returning
子句还将匹配限制为仅返回指定类型(在这种情况下,Object
匹配任何返回值)的那些方法执行。
The name used in the returning
attribute must correspond to the name of a parameter
in the advice method. When a method execution returns, the return value is passed to
the advice method as the corresponding argument value. A returning
clause also
restricts matching to only those method executions that return a value of the
specified type (in this case, Object
, which matches any return value).
请注意,在使用返回通知后不可能返回完全不同的引用。
Please note that it is not possible to return a totally different reference when using after returning advice.
After Throwing Advice
当匹配的方法执行通过抛出一个异常退出时,抛出通知运行。你可以通过使用 @AfterThrowing
注释声明它,如下面的示例所示:
After throwing advice runs when a matched method execution exits by throwing an
exception. You can declare it by using the @AfterThrowing
annotation, as the
following example shows:
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("execution(* com.xyz.dao.*.*(..))")
public void doRecoveryActions() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@Aspect
class AfterThrowingExample {
@AfterThrowing("execution(* com.xyz.dao.*.*(..))")
fun doRecoveryActions() {
// ...
}
}
通常,你希望仅在抛出给定类型的异常时才运行通知,并且还经常需要在通知正文中访问抛出的异常。你可以使用 throwing
特性来限制匹配(如果需要 - 否则将 Throwable
用作异常类型)并将抛出的异常绑定到通知参数。以下示例演示如何执行此操作:
Often, you want the advice to run only when exceptions of a given type are thrown,
and you also often need access to the thrown exception in the advice body. You can
use the throwing
attribute to both restrict matching (if desired — use Throwable
as the exception type otherwise) and bind the thrown exception to an advice parameter.
The following example shows how to do so:
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="execution(* com.xyz.dao.*.*(..))",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@Aspect
class AfterThrowingExample {
@AfterThrowing(
pointcut = "execution(* com.xyz.dao.*.*(..))",
throwing = "ex")
fun doRecoveryActions(ex: DataAccessException) {
// ...
}
}
throwing
特性中使用的名称必须与通知方法中的参数名称对应。当方法执行通过抛出一个异常退出时,异常作为相应的参数值传递给通知方法。throwing
子句还将匹配限制为仅抛出指定类型(在本例中为 DataAccessException
)异常的那些方法执行。
The name used in the throwing
attribute must correspond to the name of a parameter in
the advice method. When a method execution exits by throwing an exception, the exception
is passed to the advice method as the corresponding argument value. A throwing
clause
also restricts matching to only those method executions that throw an exception of the
specified type (DataAccessException
, in this case).
请注意, Note that |
After (Finally) Advice
当匹配的方法执行退出时,最终(finally)通知运行。它通过使用 @After
注释声明。最终通知必须准备处理正常和异常返回条件。它通常用于释放资源和类似的用途。以下示例演示如何使用最终通知:
After (finally) advice runs when a matched method execution exits. It is declared by
using the @After
annotation. After advice must be prepared to handle both normal and
exception return conditions. It is typically used for releasing resources and similar
purposes. The following example shows how to use after finally advice:
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("execution(* com.xyz.dao.*.*(..))")
public void doReleaseLock() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.After
@Aspect
class AfterFinallyExample {
@After("execution(* com.xyz.dao.*.*(..))")
fun doReleaseLock() {
// ...
}
}
请注意,AspectJ 中的 Note that |
Around Advice
最后一种通知是 around 通知。Around 通知在匹配方法的执行周围运行。它有机会在方法运行之前和之后都进行工作,并确定方法何时、如何,甚至是否真正运行。如果您需要在多线程方式下在方法执行之前和之后共享状态(例如,启动和停止计时器),则经常使用 around 通知。
The last kind of advice is around advice. Around advice runs "around" a matched method’s execution. It has the opportunity to do work both before and after the method runs and to determine when, how, and even if the method actually gets to run at all. Around advice is often used if you need to share state before and after a method execution in a thread-safe manner – for example, starting and stopping a timer.
始终使用满足您要求中最不强大的通知形式。 Always use the least powerful form of advice that meets your requirements. 例如,如果 before 通知足以满足您的需要,请勿使用 around 通知。 For example, do not use around advice if before advice is sufficient for your needs. |
通过使用 @Around
注解为方法添加注释来声明周围建议。该方法应声明 Object
作为其返回类型,并且该方法的第一个参数的类型必须是 ProceedingJoinPoint
。在建议方法的主体中,你必须在 ProceedingJoinPoint
上调用 proceed()
才能让底层方法运行。在没有参数的情况下调用 proceed()
将导致在调用底层方法时将调用者的原始参数提供给底层方法。对于高级用例,proceed()
方法有一个过载变量,它接受一个参数数组 (Object[]
)。数组中的值将在调用底层方法时用作底层方法的参数。
Around advice is declared by annotating a method with the @Around
annotation. The
method should declare Object
as its return type, and the first parameter of the method
must be of type ProceedingJoinPoint
. Within the body of the advice method, you must
invoke proceed()
on the ProceedingJoinPoint
in order for the underlying method to
run. Invoking proceed()
without arguments will result in the caller’s original
arguments being supplied to the underlying method when it is invoked. For advanced use
cases, there is an overloaded variant of the proceed()
method which accepts an array of
arguments (Object[]
). The values in the array will be used as the arguments to the
underlying method when it is invoked.
在使用 The behavior of Spring 采取的方法更简单,并且更符合它基于代理,只执行语义的方式。如果你为 Spring 编写 "@1" 切面并且使用 "@2" 与 AspectJ 编译器和织入器一起用参数,你只需要知道这个差别。针对 Spring AOP 和 AspectJ,有一种方法可以编写 100% 兼容的切面,这个方法在 "@3" 中进行了讨论。 The approach taken by Spring is simpler and a better match to its proxy-based,
execution-only semantics. You only need to be aware of this difference if you compile
|
环绕通知返回的值是由方法的调用者看到的返回值。例如,一个简单的缓存方面可以返回缓存中的值(如果有),如果没有,则调用 proceed()
(并返回该值)。请注意,可以在环绕通知的主体中一次、多次或根本不调用 proceed
。所有这些都是合法的。
The value returned by the around advice is the return value seen by the caller of the
method. For example, a simple caching aspect could return a value from a cache if it has
one or invoke proceed()
(and return that value) if it does not. Note that proceed
may be invoked once, many times, or not at all within the body of the around advice. All
of these are legal.
如果您将 around advice 方法的返回类型声明为 void
,null
总是会被返回给调用者,进而忽略了对 proceed()
的任何调用结果。因此,建议 around advice 方法声明 Object
的返回类型。advice 方法通常应该返回从对 proceed()
的调用中返回的值,即使底层方法具有 void
返回类型。然而,advice 可以根据用例有选择地返回缓存值、包装值或其他值。
If you declare the return type of your around advice method as void
, null
will always be returned to the caller, effectively ignoring the result of any invocation
of proceed()
. It is therefore recommended that an around advice method declare a return
type of Object
. The advice method should typically return the value returned from an
invocation of proceed()
, even if the underlying method has a void
return type.
However, the advice may optionally return a cached value, a wrapped value, or some other
value depending on the use case.
以下示例演示如何使用环绕通知:
The following example shows how to use around advice:
-
Java
-
Kotlin
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class AroundExample {
@Around("execution(* com.xyz..service.*.*(..))")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.ProceedingJoinPoint
@Aspect
class AroundExample {
@Around("execution(* com.xyz..service.*.*(..))")
fun doBasicProfiling(pjp: ProceedingJoinPoint): Any? {
// start stopwatch
val retVal = pjp.proceed()
// stop stopwatch
return retVal
}
}
Advice Parameters
Spring 提供全类型建议,这意味着您在建议签名中声明所需的用于建议签名的参数(如我们之前看到的返回和抛出示例)而不是始终处理 Object[]
数组。我们之后在本文中了解如何将参数和其他上下文值提供给建议主体。首先,我们了解如何编写通用建议,以查找建议当前建议的方法。
Spring offers fully typed advice, meaning that you declare the parameters you need in the
advice signature (as we saw earlier for the returning and throwing examples) rather than
work with Object[]
arrays all the time. We see how to make argument and other contextual
values available to the advice body later in this section. First, we take a look at how to
write generic advice that can find out about the method the advice is currently advising.
Access to the Current JoinPoint
任何通知方法都可以将其第一个参数声明为类型为 org.aspectj.lang.JoinPoint
的参数。请注意,环绕通知必须声明类型为 ProceedingJoinPoint
的第一个参数,后者是 JoinPoint
的子类。
Any advice method may declare, as its first parameter, a parameter of type
org.aspectj.lang.JoinPoint
. Note that around advice is required to declare a first
parameter of type ProceedingJoinPoint
, which is a subclass of JoinPoint
.
JoinPoint
接口提供了许多有用的方法:
The JoinPoint
interface provides a number of useful methods:
-
getArgs()
: Returns the method arguments. -
getThis()
: Returns the proxy object. -
getTarget()
: Returns the target object. -
getSignature()
: Returns a description of the method that is being advised. -
toString()
: Prints a useful description of the method being advised.
请参阅 javadoc 了解更多详细信息。
See the javadoc for more detail.
Passing Parameters to Advice
我们已经了解了如何绑定返回的值或异常值(使用 afterreturning 和 after throwing 建议)。要使参数值可用于建议正文,您可以使用 args
的绑定形式。如果您在 args
表达式中使用参数名称来代替 atype 名称,那么在调用建议时将值与对应的参数一起传递。一个示例可以使这一点更清楚。假设您希望建议执行将 Account
对象作为第一个参数的 DAO 操作的执行,并且您需要在建议正文中访问这个帐户。您可以编写以下内容:
We have already seen how to bind the returned value or exception value (using after
returning and after throwing advice). To make argument values available to the advice
body, you can use the binding form of args
. If you use a parameter name in place of a
type name in an args
expression, the value of the corresponding argument is passed as
the parameter value when the advice is invoked. An example should make this clearer.
Suppose you want to advise the execution of DAO operations that take an Account
object as the first parameter, and you need access to the account in the advice body.
You could write the following:
-
Java
-
Kotlin
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
public void validateAccount(Account account) {
// ...
}
@Before("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
fun validateAccount(account: Account) {
// ...
}
切入点表达式中的 args(account,..)
部分有两个作用。首先,它将匹配限制为只匹配方法至少有一个参数的方法执行,并且传递给该参数的参数是 Account
的实例。其次,它通过 account
参数使实际 Account
对象可以用于建议。
The args(account,..)
part of the pointcut expression serves two purposes. First, it
restricts matching to only those method executions where the method takes at least one
parameter, and the argument passed to that parameter is an instance of Account
.
Second, it makes the actual Account
object available to the advice through the account
parameter.
另一种写法是声明一个切入点,以便在与连接点匹配时“提供”Account
对象值,然后在建议中引用命名的切入点。如下所示:
Another way of writing this is to declare a pointcut that "provides" the Account
object value when it matches a join point, and then refer to the named pointcut
from the advice. This would look as follows:
-
Java
-
Kotlin
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
private void accountDataAccessOperation(Account account) {}
@Before("accountDataAccessOperation(account)")
public void validateAccount(Account account) {
// ...
}
@Pointcut("execution(* com.xyz.dao.*.*(..)) && args(account,..)")
private fun accountDataAccessOperation(account: Account) {
}
@Before("accountDataAccessOperation(account)")
fun validateAccount(account: Account) {
// ...
}
有关更多详细信息,请参阅 AspectJ 编程指南。
See the AspectJ programming guide for more details.
代理对象 (this
)、目标对象 (target
) 和注释 (@within
、@target
、@annotation
和 @args
) 都可以采用类似的方式绑定。下一组示例显示了如何匹配使用 @Auditable
注释注释的方法的执行并提取审计代码:
The proxy object (this
), target object (target
), and annotations (@within
,
@target
, @annotation
, and @args
) can all be bound in a similar fashion. The next
set of examples shows how to match the execution of methods annotated with an
@Auditable
annotation and extract the audit code:
以下代码显示了 @Auditable
注释的定义:
The following shows the definition of the @Auditable
annotation:
-
Java
-
Kotlin
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Auditable {
AuditCode value();
}
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Auditable(val value: AuditCode)
以下代码显示了匹配 @Auditable
方法的执行的建议:
The following shows the advice that matches the execution of @Auditable
methods:
- Java
-
@Before("com.xyz.Pointcuts.publicMethod() && @annotation(auditable)") (1) public void audit(Auditable auditable) { AuditCode code = auditable.value(); // ... }
1 | References the publicMethod named pointcut defined in Combining Pointcut Expressions.
|
2 | References the publicMethod named pointcut defined in Combining Pointcut Expressions. |
Advice Parameters and Generics
Spring AOP 可以处理类声明和方法参数中使用的泛型。假设您有一个类似于以下内容的泛型类型:
Spring AOP can handle generics used in class declarations and method parameters. Suppose you have a generic type like the following:
-
Java
-
Kotlin
public interface Sample<T> {
void sampleGenericMethod(T param);
void sampleGenericCollectionMethod(Collection<T> param);
}
interface Sample<T> {
fun sampleGenericMethod(param: T)
fun sampleGenericCollectionMethod(param: Collection<T>)
}
您可以通过将建议参数绑定到您要拦截方法的参数类型来将方法类型的拦截限制为某些参数类型:
You can restrict interception of method types to certain parameter types by tying the advice parameter to the parameter type for which you want to intercept the method:
-
Java
-
Kotlin
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
public void beforeSampleMethod(MyType param) {
// Advice implementation
}
@Before("execution(* ..Sample+.sampleGenericMethod(*)) && args(param)")
fun beforeSampleMethod(param: MyType) {
// Advice implementation
}
此方法不适用于泛型集合。因此,您无法定义如下切入点:
This approach does not work for generic collections. So you cannot define a pointcut as follows:
-
Java
-
Kotlin
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
public void beforeSampleMethod(Collection<MyType> param) {
// Advice implementation
}
@Before("execution(* ..Sample+.sampleGenericCollectionMethod(*)) && args(param)")
fun beforeSampleMethod(param: Collection<MyType>) {
// Advice implementation
}
为了使其正常工作,我们必须检查集合的每个元素,这是不合理的,因为我们也不能决定如何处理 null
值。为了实现与这个类似的功能,您必须将参数键入到 Collection<?>
并手动检查元素的类型。
To make this work, we would have to inspect every element of the collection, which is not
reasonable, as we also cannot decide how to treat null
values in general. To achieve
something similar to this, you have to type the parameter to Collection<?>
and manually
check the type of the elements.
Determining Argument Names
建议调用中的参数绑定依赖于将切入点表达式中使用的名称与建议和切入点方法签名中声明的参数名称相匹配。
Parameter binding in advice invocations relies on matching the names used in pointcut expressions to the parameter names declared in advice and pointcut method signatures.
本部分可互换地使用术语 argument 和 parameter,因为 AspectJ API 将参数名称为变量名。 |
This section uses the terms argument and parameter interchangeably, since AspectJ APIs refer to parameter names as argument names. |
Spring AOP 使用以下 ParameterNameDiscoverer
实现来确定参数名称。每个发现者将有机会发现参数名称,第一个成功的发现者获胜。如果未注册的发现者能够确定参数名称,则会抛出异常。
Spring AOP uses the following ParameterNameDiscoverer
implementations to determine
parameter names. Each discoverer will be given a chance to discover parameter names, and
the first successful discoverer wins. If none of the registered discoverers is capable
of determining parameter names, an exception will be thrown.
AspectJAnnotationParameterNameDiscoverer
-
Uses parameter names that have been explicitly specified by the user via the
argNames
attribute in the corresponding advice or pointcut annotation. See Explicit Argument Names for details. KotlinReflectionParameterNameDiscoverer
-
Uses Kotlin reflection APIs to determine parameter names. This discoverer is only used if such APIs are present on the classpath.
StandardReflectionParameterNameDiscoverer
-
Uses the standard
java.lang.reflect.Parameter
API to determine parameter names. Requires that code be compiled with the-parameters
flag forjavac
. Recommended approach on Java 8+. AspectJAdviceParameterNameDiscoverer
-
Deduces parameter names from the pointcut expression,
returning
, andthrowing
clauses. See the javadoc for details on the algorithm used.
Explicit Argument Names
@AspectJ 建议和切入点注释具有可选的 argNames
属性,可以用来指定带注释的方法的参数名称。
@AspectJ advice and pointcut annotations have an optional argNames
attribute that you
can use to specify the argument names of the annotated method.
如果 @AspectJ 方面是由 AspectJ 编译器 ( If an @AspectJ aspect has been compiled by the AspectJ compiler ( 类似地,如果一个 @AspectJ 方面是使用 Similarly, if an @AspectJ aspect has been compiled with |
以下示例展示了如何使用 argNames
属性:
The following example shows how to use the argNames
attribute:
- Java
-
@Before( value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", (1) argNames = "bean,auditable") (2) public void audit(Object bean, Auditable auditable) { AuditCode code = auditable.value(); // ... use code and bean }
1 | References the publicMethod named pointcut defined in Combining Pointcut Expressions. |
2 | Declares bean and auditable as the argument names.
|
3 | References the publicMethod named pointcut defined in Combining Pointcut Expressions. |
4 | Declares bean and auditable as the argument names. |
如果第一个参数的类型是 JoinPoint
、ProceedingJoinPoint
或 JoinPoint.StaticPart
,则可以从 argNames
属性的值中省略参数的名称。例如,如果您修改前面的建议以接收连接点对象,则 argNames
属性不必包含它:
If the first parameter is of type JoinPoint
, ProceedingJoinPoint
, or
JoinPoint.StaticPart
, you can omit the name of the parameter from the value of the
argNames
attribute. For example, if you modify the preceding advice to receive the join
point object, the argNames
attribute does not need to include it:
- Java
-
@Before( value = "com.xyz.Pointcuts.publicMethod() && target(bean) && @annotation(auditable)", (1) argNames = "bean,auditable") (2) public void audit(JoinPoint jp, Object bean, Auditable auditable) { AuditCode code = auditable.value(); // ... use code, bean, and jp }
1 | References the publicMethod named pointcut defined in Combining Pointcut Expressions. |
2 | Declares bean and auditable as the argument names.
|
3 | References the publicMethod named pointcut defined in Combining Pointcut Expressions. |
4 | Declares bean and auditable as the argument names. |
对于类型为 JoinPoint
、ProceedingJoinPoint
或 JoinPoint.StaticPart
的第一个参数给予的特殊处理对于不收集任何其他连接点上下文的建议方法来说特别方便。在这种情况下,您可以省略 argNames
属性。例如,以下建议不必声明 argNames
属性:
The special treatment given to the first parameter of type JoinPoint
,
ProceedingJoinPoint
, or JoinPoint.StaticPart
is particularly convenient for advice
methods that do not collect any other join point context. In such situations, you may
omit the argNames
attribute. For example, the following advice does not need to declare
the argNames
attribute:
- Java
-
@Before("com.xyz.Pointcuts.publicMethod()") (1) public void audit(JoinPoint jp) { // ... use jp }
1 | References the publicMethod named pointcut defined in Combining Pointcut Expressions.
|
2 | References the publicMethod named pointcut defined in Combining Pointcut Expressions. |
Proceeding with Arguments
我们前面说过将描述如何编写 proceed
调用,它的参数可以在 Spring AOP 和 AspectJ 中保持一致。解决方案是确保建议签名按顺序绑定每个方法参数。以下示例展示了如何执行此操作:
We remarked earlier that we would describe how to write a proceed
call with
arguments that works consistently across Spring AOP and AspectJ. The solution is
to ensure that the advice signature binds each of the method parameters in order.
The following example shows how to do so:
- Java
-
@Around("execution(List<Account> find*(..)) && " + "com.xyz.CommonPointcuts.inDataAccessLayer() && " + "args(accountHolderNamePattern)") (1) public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern) throws Throwable { String newPattern = preProcess(accountHolderNamePattern); return pjp.proceed(new Object[] {newPattern}); }
1 | References the inDataAccessLayer named pointcut defined in Sharing Named Pointcut Definitions.
|
2 | References the inDataAccessLayer named pointcut defined in Sharing Named Pointcut Definitions. |
在许多情况下,你无论如何都会进行此绑定(如前面的示例所示)。
In many cases, you do this binding anyway (as in the preceding example).
Advice Ordering
当多条建议都希望在同一连接点运行时会发生什么?Spring AOP 遵循与 AspectJ 相同的优先级规则,以确定建议执行的顺序。优先级最高的建议在“进入”时首先运行(因此,给定两条 before 建议,优先级最高的建议首先运行)。从连接点“退出”时,优先级最高的建议最后执行(因此,给定两条 after 建议,优先级最高的建议将第二个运行)。
What happens when multiple pieces of advice all want to run at the same join point? Spring AOP follows the same precedence rules as AspectJ to determine the order of advice execution. The highest precedence advice runs first "on the way in" (so, given two pieces of before advice, the one with highest precedence runs first). "On the way out" from a join point, the highest precedence advice runs last (so, given two pieces of after advice, the one with the highest precedence will run second).
当定义在不同方面中的两条建议都需要在同一连接点运行时,除非你另有指定,否则执行顺序是不确定的。你可以通过指定优先级来控制执行顺序。这是通过正常 Spring 方式完成的,即在方面类中实现 org.springframework.core.Ordered
接口或对其进行 @Order
注释。给定两个方面,从 Ordered.getOrder()
(或注释值)返回较低值的方面具有较高的优先级。
When two pieces of advice defined in different aspects both need to run at the same
join point, unless you specify otherwise, the order of execution is undefined. You can
control the order of execution by specifying precedence. This is done in the normal
Spring way by either implementing the org.springframework.core.Ordered
interface in
the aspect class or annotating it with the @Order
annotation. Given two aspects, the
aspect returning the lower value from Ordered.getOrder()
(or the annotation value) has
the higher precedence.
某个方面的不同建议类型在概念上打算直接应用于连接点。因此, Each of the distinct advice types of a particular aspect is conceptually meant to apply
to the join point directly. As a consequence, an 从 Spring Framework 5.2.7 开始,在同一 As of Spring Framework 5.2.7, advice methods defined in the same 当在同一 When two pieces of the same type of advice (for example, two |