AOP通知方法如何执行
先看下整体的AOP
基本通知方法的内部执行顺序结构:
我们拿JDK
动态代理为例,CGLIB
也是类似,当调用某个方法的时候,会进行JdkDynamicAopProxy
代理的invoke
执行:
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
一堆,其实重要的就这么几句,首先获取所有通知List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
然后封装成ReflectiveMethodInvocation
调用proceed
方法。我把AOP的一般方法都用上了,可以看到这里他已经是排序完的,具体怎么排序的,可以去研究下,比较复杂,其实就是为了形成一个调用栈顺序,后面我会画出来,我们先看这些用到的,第一个其实没什么具体用,他会直接执行第二个,然后顺序执行下去:
ReflectiveMethodInvocation的proceed循环执行
主要是递归获取通知,然后执行。
@Override
@Nullable
public Object proceed() throws Throwable {
// 循环执行,直到执行完
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//获得通知方法
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {//执行
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
ExposeInvocationInterceptor的invoke
没做什么,主要是mi.proceed()
,也就是继续调用ReflectiveMethodInvocation的proceed
来进行递归调用。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
AspectJAfterThrowingAdvice的invoke异常通知
其实就是在外面包了一层捕获异常,然后继续调用mi.proceed();
,如果出异常了可以捕获到执行invokeAdviceMethod
。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
AbstractAspectJAdvice的invokeAdviceMethod通知方法
其实这个是通用的通知方法,只要有要调用的通知方法,都会去调用这个内部最终调用了这个:
AfterReturningAdviceInterceptor的invoke成功返回后通知
只是在返回后加了方法,内部就是调用invokeAdviceMethod
。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
AspectJAfterAdvice的invoke方法后通知
就是在执行完后执行invokeAdviceMethod
。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
AspectJAroundAdvice的invoke环绕通知
这个会先把MethodInvocation
封装成ProceedingJoinPoint
,然后在调用的时候当做参数传进去。
@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);
}
先封装:
后使用:
然后里面会进行克隆,或许是代理为了保护源数据信息吧,然后再调用proceed
:
MethodBeforeAdviceInterceptor的invoke方法前通知
先调用方法前通知方法,在调用方法。
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
基本的流程就是这样下来的,所以为什么环绕是在最前面,因为环绕代理了后面要执行的方法,提前进行了环绕前处理:
如果有异常的话:
再看下整个结构是这样的:
HM6Ly9ibG9nLmNzZG4ubmV0L3dhbmd3ZWkxOTg3MTEwMw==,size_16,color_FFFFFF,t_70)
正常情况可以对照,就是没有异常的,没啥问题。
如果出现异常,就是出现在System.out.println("方法调用");
因此直接执行System.out.println("logAfter");
,不会去执行logReturning
,直接进到catch
里面了,跟异常时候的信息也对的起来。
好了,基本的AOP
调用分析完了,其实就是通知方法排序好之后,递归调用。其实还有其他的功能,比如DeclareParents
,target
,args
等注解功能,这个基础的有了,应该不难,自己研究下好了。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。