目录
  1. 前言
  2. 区别
  3. 执行顺序
spring AOP(4) advice

前言

在spring AOP中有这样五个advice:

  • Around
  • Before
  • After
  • AfterReturning
  • AfterThrowing

区别

我们直接从源码来看看这五种advice的区别吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Around
public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
JoinPointMatch jpm = getJoinPointMatch(pmi);
return invokeAdviceMethod(pjp, jpm, null, null);
}

// Before
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}

// After
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

// AfterReturning
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}

// AfterThrowing
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable t) {
if (shouldInvokeOnThrowing(t)) {
invokeAdviceMethod(getJoinPointMatch(), null, t);
}
throw t;
}
}

在这五种advice中,我们可以看出除了Around之外,其他都会回调mi.proceed方法。而Around则可以非常自由,甚至可以完全阻断原方法的执行(同时还会阻断Before的执行)。

对于After系列的方法,我们可以发现AfterReturning和AfterThrowing的执行条件是一种互补的关系,而After则无论如何都会执行。

执行顺序

我们在shouldSkip获取advisors的过程中会调用ReflectiveAspectJAdvisorFactory的getAdvisorMethods方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private List<Method> getAdvisorMethods(Class<?> aspectClass) {
final List<Method> methods = new LinkedList<Method>();
ReflectionUtils.doWithMethods(aspectClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException {
// Exclude pointcuts
if (AnnotationUtils.getAnnotation(method, Pointcut.class) == null) {
methods.add(method);
}
}
});
Collections.sort(methods, METHOD_COMPARATOR);
return methods;
}

在这段代码中我们可以发现其中有一个排序的过程,我们找到METHOD_COMPARATOR的定义(仍然在ReflectiveAspectJAdvisorFactory类中),可以看到如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static final Comparator<Method> METHOD_COMPARATOR;

static {
CompoundComparator<Method> comparator = new CompoundComparator<Method>();
comparator.addComparator(new ConvertingComparator<Method, Annotation>(
new InstanceComparator<Annotation>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
new Converter<Method, Annotation>() {
@Override
public Annotation convert(Method method) {
AspectJAnnotation<?> annotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return annotation == null ? null : annotation.getAnnotation();
}
}));
comparator.addComparator(new ConvertingComparator<Method, String>(
new Converter<Method, String>() {
@Override
public String convert(Method method) {
return method.getName();
}
}));
METHOD_COMPARATOR = comparator;
}

其中比较器使用的是InstanceComparator,初始化参数为Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class。我们打开InstanceComparator,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class InstanceComparator<T> implements Comparator<T> {

private Class<?>[] instanceOrder;

public InstanceComparator(Class<?>... instanceOrder) {
Assert.notNull(instanceOrder, "InstanceOrder must not be null");
this.instanceOrder = instanceOrder;
}


@Override
public int compare(T o1, T o2) {
int i1 = getOrder(o1);
int i2 = getOrder(o2);
return (i1 < i2 ? -1 : (i1 == i2 ? 0 : 1));
}

private int getOrder(T object) {
if(object != null) {
for (int i = 0; i < instanceOrder.length; i++) {
if (instanceOrder[i].isInstance(object)) {
return i;
}
}
}
return instanceOrder.length;
}
}

可以看到比较顺序是由参数的传递顺序决定的。

但其实到这里我们仍然不能说advice的执行顺序是Around$\rightarrow$BeforeAfter$\rightarrow$AfterReturning$\rightarrow$AfterThrowing。

为什么呢?

如果我们仔细想一想After系列的代码,After系列函数的代码是先执行proceed再执行本身的。

那么这样的话,如果按照上面所说的顺序的话,最后执行出来的结果应该是Around$\rightarrow$Before$\rightarrow$AfterThrowing$\rightarrow$AfterReturning$\rightarrow$After。那么其实这样的顺序是不正确的,上面所说的那个顺序才是正确的。

不过,其实排序的部分并不止这一部分,我们直接找到AspectJPrecedenceComparator这个类,找到里面的compare方法,

1
2
3
4
5
6
7
public int compare(Advisor o1, Advisor o2) {
int advisorPrecedence = this.advisorComparator.compare(o1, o2);
if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
}
return advisorPrecedence;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
boolean oneOrOtherIsAfterAdvice =
(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);

if (oneOrOtherIsAfterAdvice) {
// the advice declared last has higher precedence
if (adviceDeclarationOrderDelta < 0) {
// advice1 was declared before advice2
// so advice1 has lower precedence
return LOWER_PRECEDENCE;
}
else if (adviceDeclarationOrderDelta == 0) {
return SAME_PRECEDENCE;
}
else {
return HIGHER_PRECEDENCE;
}
}
else {
// the advice declared first has higher precedence
if (adviceDeclarationOrderDelta < 0) {
// advice1 was declared before advice2
// so advice1 has higher precedence
return HIGHER_PRECEDENCE;
}
else if (adviceDeclarationOrderDelta == 0) {
return SAME_PRECEDENCE;
}
else {
return LOWER_PRECEDENCE;
}
}
}

可以看到这部分,对于After系列的advice,它会进行反序,由于前面排序调用涉及的方法比较多,此处不详解。

最后的结果就是拦截器最终排出来的顺序是AfterThrowing$\rightarrow$AfterReturning$\rightarrow$After$\rightarrow$Around$\rightarrow$Before。

这样的话,根据递归的逻辑,最终advice的执行顺序便为Around$\rightarrow$Before$\rightarrow$After$\rightarrow$AfterReturning$\rightarrow$AfterThrowing。

其中Around会阻断Before的执行,但是不能阻断After系列advice的执行。

文章作者: 谷河
文章链接: https://www.lyytaw.com/spring/spring_aop_advice/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 谷河|BLOG