這次來(lái)分析下切面的執(zhí)行過(guò)程。
1.怎么看?
怎么開(kāi)始看源碼呢?就直接從被增強(qiáng)的方法調(diào)用那里打斷點(diǎn),看看怎么執(zhí)行的:
然后就來(lái)到了這:
2.初步分析
里面有段:
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
就是上篇文章講到的注解配置暴露代理對(duì)象,放到AopContext的ThreadLocal里去,之后就可以隨時(shí)用 AopContext.currentProxy())取到代理對(duì)象。
接下來(lái)有段重要的:
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
獲取攔截器鏈,就是把這次相關(guān)的增強(qiáng)器轉(zhuǎn)化成攔截器獲取出來(lái)
然后:
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...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
這里就是判斷攔截器鏈有沒(méi)有東西,如果是空的就直接通過(guò)反射調(diào)用,不是空就進(jìn)行else邏輯了,那else是重點(diǎn)了,即invocation.proceed();
3.invocation.proceed()
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
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;
if (dm.methodMatcher.matches(this.method, this.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);
}
}
第一個(gè)if是遞歸的終止條件,明顯是根據(jù)下標(biāo)進(jìn)行終止的條件
后面進(jìn)行前++,又調(diào)用了
((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
然而這里面是:
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
又跑回proceed方法去了,遞歸。
第二次來(lái)到的時(shí)候下標(biāo)就是0了(第一次是-1,默認(rèn)的),前++為1的下標(biāo)的話,取出來(lái)的東西繼續(xù)調(diào)用invoke發(fā)現(xiàn)進(jìn)的是AspectJAfterThrowingAdvice的invoke了(第一次是ExposeInvocationInterceptor的invoke,記錄下MethodInvocation供后面執(zhí)行鏈獲?。?/p>
這個(gè)AspectJAfterThrowingAdvice的invoke的源碼如下(不一樣):
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
繼續(xù)遞歸,不過(guò)這次把調(diào)用鏈try起來(lái)了,出異常就走異常增強(qiáng)通知invokeAdviceMethod
繼續(xù)debug,又是遞歸到invoke,但這次是AfterReturningAdviceInterceptor的:
public Object invoke(MethodInvocation mi) throws Throwable {
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
提一下啊,遞歸是棧結(jié)構(gòu)!所以我們先看到了異常調(diào)用代碼和返回通知代碼!
繼續(xù)遞歸proceed到了后置通知AspectJAfterAdvice類的invoke:
public Object invoke(MethodInvocation mi) throws Throwable {
try {
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
看到?jīng)],后置通知類的invokeAdviceMethod調(diào)用是用的finally,所以后置通知始終執(zhí)行!
繼續(xù)遞歸
跳到了前置通知類MethodBeforeAdviceInterceptor的invoke
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
注意這里不一樣了!它是先調(diào)用自己再調(diào)執(zhí)行鏈,這也就是為什么前置通知早于方法執(zhí)行
before方法執(zhí)行完之后,進(jìn)proceed了,遞歸即將結(jié)束:
所有的增強(qiáng)器取出來(lái)了,并執(zhí)行了before 這里遞歸就結(jié)束了,調(diào)用目標(biāo)方法:invokeJoinpoint
然后是后置通知各種,有異常就走之前try finally那里。
至此aop具體邏輯結(jié)束!
總結(jié)下易翻車點(diǎn):
1.注意看自己的源碼是哪個(gè)類,不然很懵逼,因?yàn)檎{(diào)了很多個(gè)類的同名方法invoke。
2.注意看是遞歸,和遞歸結(jié)束條件
3.注意invoke的實(shí)現(xiàn),對(duì)于不同的增強(qiáng)器的邏輯是不一樣的
4.增強(qiáng)器那個(gè)集合是有順序好的