SpringAOP 源码之常用的 Advice

介绍常用的 Advice

img

AspectJMethodBeforeAdvice, AspectJAfterReturningAdvice 没有实现 MethodInterceptor 接口, 在构造调用链时会通过 MethodBeforeAdviceAdapter, AfterReturningAdviceAdapter 这两个适配器转换成对应的接口,通过调用 MethodInterceptor#invoke 方法来实现对各个方法的处理

AspectJMethodBeforeAdvice

定位: org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor#invoke

1
2
3
4
5
6
7
8
// invoke 方法是拦截器的回调方法,会在代理对应的方法被调用时触发回调
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
// 执行前置通知的方法
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
// 执行下一个通知/拦截器,如果该拦截器是最后一个了,将会调用目标方法
return mi.proceed();
}

定位: org.springframework.aop.aspectj.AspectJMethodBeforeAdvice#before

1
2
3
4
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
// 这里传进来的目标对象、目标参数、目标方法都没有用到
invokeAdviceMethod(getJoinPointMatch(), null, null);
}

AspectJAfterReturningAdvice

定位: org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor

1
2
3
4
5
6
7
public Object invoke(MethodInvocation mi) throws Throwable {
// 执行下一个通知/拦截器
Object retVal = mi.proceed();
// 返回通知方法
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}

定位: org.springframework.aop.aspectj.AspectJAfterReturningAdvice#afterReturning

1
2
3
4
5
public void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable {
if (shouldInvokeOnReturnValueOf(method, returnValue)) {
invokeAdviceMethod(getJoinPointMatch(), returnValue, null);
}
}

AspectJAfterThrowingAdvice

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行下一个通知/拦截器 methodInvocation
return mi.proceed();
}
catch (Throwable ex) {
// 抛出异常
if (shouldInvokeOnThrowing(ex)) {
// 执行异常通知
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}

AspectJAfterAdvice

1
2
3
4
5
6
7
8
9
10
11
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 执行下一个通知/拦截器,如果该拦截器是最后一个了,将会调用目标方法
return mi.proceed();
}
finally {
// 执行后置通知的方法
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}

AspectJAroundAdvice

1
2
3
4
5
6
7
8
9
10
@Override
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);
}

AbstractAspectJAdvice

invokeAdviceMethod

定位: org.springframework.aop.aspectj.AbstractAspectJAdvice#invokeAdviceMethod

调用 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
protected Object invokeAdviceMethod(JoinPoint jp, @Nullable JoinPointMatch jpMatch,
@Nullable Object returnValue, @Nullable Throwable t) throws Throwable {

return invokeAdviceMethodWithGivenArgs(argBinding(jp, jpMatch, returnValue, t));
}
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
// 判断通知方法是否有参数
if (this.aspectJAdviceMethod.getParameterCount() == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// TODO AopUtils.invokeJoinpointUsingReflection
// 反射调用通知方法
// this.aspectInstanceFactory.getAspectInstance() 获取的是切面的实例
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}

getJoinPointMatch

定位: org.springframework.aop.aspectj.AbstractAspectJAdvice#getJoinPointMatch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected JoinPointMatch getJoinPointMatch() {
// 这里是怎么获取到 MethodInvocation 的对象的呢?
// 我们在获取 Advisor 的时候,调用过方法 org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
// 在这个方法中会有这样的一段代码, 如果存在 AspectJAdvice, 则将 ExposeInvocationInterceptor.ADVISOR 放到 Advisor 链的第一个
// 这样我们就不难理解了,在调用 ReflectiveMethodInvocation#proceed 的时候第一个调用的 MethodInterceptor 是 ExposeInvocationInterceptor
// 会将 MethodInvocation 放到线程变量中
MethodInvocation mi = ExposeInvocationInterceptor.currentInvocation();
if (!(mi instanceof ProxyMethodInvocation)) {
throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
}
// 这里主要是获取 JoinPointMatch
return getJoinPointMatch((ProxyMethodInvocation) mi);
}
protected JoinPointMatch getJoinPointMatch(ProxyMethodInvocation pmi) {
String expression = this.pointcut.getExpression();
return (expression != null ? (JoinPointMatch) pmi.getUserAttribute(expression) : null);
}