引
接前面一章繼續(xù)分析SpringAOP獲取攔截器鏈和攔截器鏈的調(diào)用過程营勤。
1.獲取攔截器鏈
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
/**
* 獲取攔截器鏈
*/
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
// 獲取AdvisorAdapterRegistry對象,Spring默認(rèn)初始化了MethodBeforeAdviceAdapter,AfterReturningAdviceAdapter和ThrowsAdviceAdapter
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
// 獲取所有增強(qiáng)
Advisor[] advisors = config.getAdvisors();
// 創(chuàng)建interceptorList保存返回結(jié)果,這里可以看到new ArrayList指定了集合長度,也是編碼中節(jié)約內(nèi)存開銷的一個(gè)小技巧
List<Object> interceptorList = new ArrayList<>(advisors.length);
// 獲取代理類的Class對象
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
// 循環(huán)所有的增強(qiáng)
for (Advisor advisor : advisors) {
// 如果增強(qiáng)是PointcutAdvisor的實(shí)例
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
// config.isPreFiltered() -> 返回是否對該代理配置進(jìn)行了預(yù)篩選,以便僅對其進(jìn)行篩選包含適用的增強(qiáng)(匹配此代理的目標(biāo)類)。
// pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) -> 當(dāng)前切點(diǎn)匹配的類是否匹配actualClass
// 以上兩個(gè)條件是在類一級別上做出判斷,如果符合,則接下來對方法級別的再做匹配判斷
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
// 獲取當(dāng)前切點(diǎn)匹配的方法
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
boolean match;
// 區(qū)分普通的MethodMatcher和IntroductionAwareMethodMatcher,分別調(diào)用不同的匹配方法做出判斷
// IntroductionAwareMethodMatcher可以作用域引入類型的增強(qiáng),且當(dāng)匹配方法不包含引用增強(qiáng)時(shí),可以提升匹配效率
if (mm instanceof IntroductionAwareMethodMatcher) {
if (hasIntroductions == null) {
hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
}
match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);
}
else {
match = mm.matches(method, actualClass);
}
// 如果匹配
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
// 如果增強(qiáng)是IntroductionAdvisor實(shí)例
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
// 其他類型
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
該段代碼比較關(guān)鍵的點(diǎn):
// 如果匹配,獲取方法攔截器
if (match) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
通過上面的代碼可以發(fā)現(xiàn)Spring最終還是要把增強(qiáng)(切面)轉(zhuǎn)換為方法攔截器撵幽,來看其具體的實(shí)現(xiàn):
/**
* 獲取方法連接器
*/
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
// 1.如果增強(qiáng)是MethodInterceptor類型直接添加
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
// 2.循環(huán)增強(qiáng)適配器,并判斷是否支持
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
// 3.返回結(jié)果
return interceptors.toArray(new MethodInterceptor[0]);
}
通過這段代碼痴荐,如果增強(qiáng)是MethodInterceptor的實(shí)例烘豌,直接加入結(jié)果中华蜒;那么哪些增強(qiáng)是MethodInterceptor類型呢辙纬?先不用著急,繼續(xù)看下面的處理叭喜,下面的代碼里出現(xiàn)了一個(gè)增強(qiáng)適配器贺拣,我們來看一下其中都包含了哪些適配器類型:
private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
DefaultAdvisorAdapterRegistry通過構(gòu)造函數(shù)對增強(qiáng)適配器進(jìn)行了初始化,包含了MethodBeforeAdviceAdapter前置增強(qiáng)適配器域滥、AfterReturningAdviceAdapter后置返回增強(qiáng)適配器纵柿、ThrowsAdviceAdapter后置異常增強(qiáng)適配器蜈抓。那么從這里我們也可以推斷出启绰,除了這幾種增強(qiáng)適配器對應(yīng)的增強(qiáng)類型之外,其他的都是MethodInterceptor類型沟使。
接下來看下這三種適配器都做了哪些工作:
- MethodBeforeAdviceAdapter
/**
* 增強(qiáng)適配器
* 這個(gè)方法在獲取攔截器鏈的時(shí)候調(diào)用,從這里也可以看出,Spring中的advisor(增強(qiáng)/切面)
* 最終還是被轉(zhuǎn)換為MethodInterceptor對象
*
* AdvisorAdapter的實(shí)現(xiàn)類有AfterReturningAdviceAdapter,MethodBeforeAdviceAdapter,ThrowsAdviceAdapter三個(gè)
*
* AfterReturningAdviceAdapter -> new AfterReturningAdviceInterceptor(advice) -> 后置返回增強(qiáng)
* MethodBeforeAdviceAdapter -> new MethodBeforeAdviceInterceptor(advice) -> 前置增強(qiáng)
* ThrowsAdviceAdapter -> new ThrowsAdviceInterceptor(advisor.getAdvice()) -> 該適配器有些特殊...看源碼吧
*/
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
- AfterReturningAdviceAdapter
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
- ThrowsAdviceAdapter
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
return new ThrowsAdviceInterceptor(advisor.getAdvice());
}
看到這里大家一定有所了解了委可,Spring中的增強(qiáng),最終還是會轉(zhuǎn)換為方法攔截器調(diào)用腊嗡。
3. 攔截器鏈調(diào)動過程
/**
* 調(diào)用攔截器鏈
*
* currentInterceptorIndex維護(hù)了一個(gè)計(jì)數(shù)器着倾,該計(jì)數(shù)器從-1開始,當(dāng)計(jì)數(shù)器值等于攔截方法長度減一時(shí)燕少,
* 表名所有的增強(qiáng)方法已經(jīng)被調(diào)用(但是不一定被真正執(zhí)行)卡者,那么此時(shí)調(diào)用連接點(diǎn)的方法,針對本例:即sayHello方法
*/
@Override
@Nullable
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);
// 動態(tài)匹配增強(qiáng)
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());
// 匹配成功則執(zhí)行
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
// 匹配失敗則跳過并執(zhí)行下一個(gè)攔截器
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
// 靜態(tài)增強(qiáng)
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
// System.out.println(interceptorOrInterceptionAdvice.getClass());
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
這段代碼看似簡單客们,但是如果真的debug進(jìn)去崇决,方法棧還是比較深刻的,前面介紹過在獲取到合適的增強(qiáng)集合之后底挫,首先在其首位加入了ExposeInvocationInterceptor攔截器恒傻,然后對增強(qiáng)集合進(jìn)行了排序(當(dāng)然ExposeInvocationInterceptor依然會在首位),那么接下來第一個(gè)攔截器調(diào)用就是ExposeInvocationInterceptor了建邓。
- ExposeInvocationInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
MethodInvocation oldInvocation = invocation.get();
invocation.set(mi);
try {
// 繼續(xù)攔截器鏈調(diào)用
return mi.proceed();
}
finally {
invocation.set(oldInvocation);
}
}
- AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 繼續(xù)攔截器鏈調(diào)用
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
- AspectJAfterThrowingAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 繼續(xù)攔截器鏈調(diào)用
return mi.proceed();
}
catch (Throwable ex) {
if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, ex);
}
throw ex;
}
}
- AfterReturningAdviceInterceptor
public Object invoke(MethodInvocation mi) throws Throwable {
// 繼續(xù)攔截器鏈調(diào)用
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
- AspectJAfterAdvice
public Object invoke(MethodInvocation mi) throws Throwable {
try {
// 繼續(xù)攔截器鏈調(diào)用
return mi.proceed();
}
finally {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
}
- AspectJAroundAdvice
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);
}
在這里終于看到了方法的調(diào)用:
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
// 調(diào)用代理方法
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();
}
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
代碼終于執(zhí)行到了Method類的invoke方法盈厘,接下來就可以調(diào)用我們的增強(qiáng)方法了:
- MethodBeforeAdviceInterceptor
@Around("test()")
public Object aroundTest(ProceedingJoinPoint p) throws Throwable {
System.out.println("==環(huán)繞增強(qiáng)開始");
// 繼續(xù)攔截器鏈調(diào)用
Object o = p.proceed();
System.out.println("==環(huán)繞增強(qiáng)結(jié)束");
return o;
}
執(zhí)行完之后,我們發(fā)現(xiàn)前置增強(qiáng)還沒有被調(diào)用進(jìn)來官边,繼續(xù):
public Object invoke(MethodInvocation mi) throws Throwable {
// 調(diào)用前置增強(qiáng)
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
- 目標(biāo)方法
執(zhí)行完前置增強(qiáng)之后沸手,再次進(jìn)入到proceed方法,這時(shí)候注簿,計(jì)數(shù)器已經(jīng)滿足條件了契吉,執(zhí)行目標(biāo)方法調(diào)用:
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
待執(zhí)行完目標(biāo)方法調(diào)用后,再將之前壓入方法棧的那些增強(qiáng)方法依次出棧并調(diào)用滩援。這一段的代碼調(diào)用用文字表述挺困難的栅隐,大家自己跟蹤代碼吧。。租悄。
到這里攔截器鏈的調(diào)用過程分析就結(jié)束了谨究,這里分析的不是那么明確,還是多跟蹤代碼吧泣棋。