SpringAop註解源碼

分析貼

https://blog.csdn.net/jy02268879/article/details/88409710

https://www.cnblogs.com/nullllun/p/9222627.html

 

概述

在Bean初始化階段,Spring爲Bean生成代理對象,一個bean對象對應一個代理對象,代理對象的advisors:List中保存所有掃描到的和bean.class相關的AOP通知方法(Advisor)信息。每個通知方法中各自保存自己與bean.class中所有方法匹配的結果(yes\no)。給被代理方法生成調用鏈時,遍歷當前代理對象中advisors:List,通過各個AOP通知方法匹配結果,決定某個AOP通知方法是否加入調用鏈。

匹配流程:aopProxy(bean) -> dynamicAdvisedIntercepto -> advised -> 遍歷通知方法advisors[i] -> 切點pointcut.shadowMatchCache -> shadowMatchImpl.match(yes/no)

創建代理對象

通知方法排序

spring aop會在AnnotationAwareAspectJAutoProxyCreator處理bean查找到適配的Advisor的時候對所有Advisor進行排序並生成動態代理,AspectJAwareAdvisorAutoProxyCreator的sortAdvisors方法

@Override
    @SuppressWarnings("unchecked")
    protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
        List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
                new ArrayList<PartiallyComparableAdvisorHolder>(advisors.size());

        //遍歷advisors 放入partiallyComparableAdvisors 
        for (Advisor element : advisors) {
            partiallyComparableAdvisors.add(
                    new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));  //默認比較器
        }

        //排序partiallyComparableAdvisors
        List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
        if (sorted != null) {
            List<Advisor> result = new ArrayList<Advisor>(advisors.size());

            //遍歷排序後partiallyComparableAdvisors,取出Advisor存入result 
            for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
                result.add(pcAdvisor.getAdvisor());
            }
            return result;
        }
        else {
            //直接排序advisors
            return super.sortAdvisors(advisors);
        }
    }

這裏會根據每個Advisor的獲取到的order值進行從小到大排序,order值獲取規則如下:

  1. 首先判斷當前Advisor所在的切面類是否實現org.springframework.core.Ordered接口,是的話調用getOrder方法獲取
  2. 否則判斷當前Advisor所在的切面類是否包含org.springframework.core.annotation.Order註解,是的話從註解獲取
  3. 沒有取到值,默認爲最低優先級,值爲最大Int

從排序代碼可知,有以下處理過程:

  1. 打在Advice方法上的org.springframework.core.annotation.Order註解不予識別
  2. 如果一個切面類存在多個Advisor,則會按Advice方法的聲明順序,聲明在前的優先級高,先執行
  3. 不同切面類但是order值是一樣的,則按spring獲取到切面bean的順序做排序,先獲取先執行

 

 

調用過程

代理類結構

CGLIB代理對象:與Bean對象一對一。代理對象中保存了與被代理Bean相關的攔截器、派發器

aopProxy.dynamicAdvisedInterceptor.advisors: 

ArrayList中保存所有和當前被代理Bean.class相關的AOP通知方法(Advisor)信息,自定義AOP方法被Spring封裝類型爲InstantiationModelAwarePointcutAdvisor類型對象。默認order=int.max。點開事務通知方法其order=2147483647(int.max)。

aopProxy.dynamicAdvisedInterceptor.advisors[2]:

自定義AOP通知方法被Spring封裝爲InstantiationModelAwarePointcutAdvisor類型對象。下圖是自定義通知方法的屬性。

advisors[2].pointcut:自定義AOP通知方法的切點信息

其中shadowMatchCache:Map中保存着當前通知方法配置切點與被代理Bean.class中各個方法的匹配結果。匹配結果是創建AOP通知鏈的依據。其key=Bean.class中各個方法對象

 

調用核心流程

通過AOP包裝的SpringBean對象調用方法時,首先執行其代理對象的動態通知攔截器的攔截方法

CglibAopProxy.DynamicAdvisedInterceptor#intercept

1、取得AOP通知方法攔截器鏈

//通過DynamicAdvisedInterceptor.advised取得當前被代理方法tagetMethod的通知方法攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      //緩存中匹配tagetMethod攔截器鏈
      ->List<Object> cached = this.methodCache.get(cacheKey);
      //沒有命中緩存
      ->if (cached == null)
          //生成攔截器鏈cached 
          ->cached =this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
					this, method, targetClass);
                  //遍歷代理對象中保存的類相關通知方法信息
                  ->for (advisor:advisors)  
                          //通知方法切點表達式 與 目標方法匹配 ?
                          -> if (advisor.pointcut.shadowMatchCache.get(tagetMethod).match==YES ) 
                                 ->cached.add(advisor)

          //攔截器鏈存入緩存
          ->this.methodCache.put(cacheKey, cached);
          ->return cached;

2、若攔截器鏈chain爲空,直接method/methodProxy.invoke反射執行目標方法return。

3、攔截器鏈chain不爲空,實例化一個MethodInvocation  mi(每次調用都新實例化mi),遞歸其proceed()。mi中包含一個index(執行標記)、執行鏈chain.....等。

chain:ArrayList 保存順序: Expose攔截器(0)->事務攔截器(1)->after攔截器(2)->around攔截器(3)->before攔截器(4),遞歸調用mi.proceed()。

數組+index+遞歸 實現鏈式調用

(2)after攔截器invoke:先遞進mi.proceed() -> chain[++index].invoke(),finally等待迴歸出棧時執行

(3)around攔截器invoke:反射執行@Around切面方法,切面方法中調用joinPoint.proceed(),繼續遞歸mi.proceed -> chain[++index].invoke()

(4)before攔截器invoke: 由(3)遞歸進入mi.proceed(),若chain中還有攔截器(before),執行before切面方法 -> 遞歸mi.proceed() -> chain[++index].invoke()。

(5)最終mi.proceed()執行到chain末尾,index==chain.size,開始執行目標方法,return方法出棧。

 

所以SpringAOP的執行順序:around前->before->目標方法->around後->after

//每次調用都實例化一個方法調用器MethodInvocation,遞歸調用proceed
new CglibMethodInvocation(....).proceed();

//ReflectiveMethodInvocation#proceed
public Object proceed() throws Throwable {
		//this.currentInterceptorIndex =當前index 初始=-1
	        //this.interceptorsAndDynamicMethodMatchers=上邊產生的攔截器鏈chain

                 //判斷攔截器鏈是否調用完
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                        //執行目標方法,終止遞歸,方法出棧
			return invokeJoinpoint();
		}

                //取出當前index+1的攔截器
		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 {
				//匹配失敗,跳過當前攔截器,遞歸攔截器鏈下一個
				return proceed();
			}
		}
		else {
                        //攔截器類型檢測爲靜態匹配
			//執行攔截器,將this傳入,invoke中遞歸當前方法this.proceed()
                        //此invoke根據MethodInterceptor類型不同,執行也不同
                        //Expose、@Around、@Before、@After......見下面各個invoke()
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
}


//ExposeInvocationInterceptor#invoke
//Expose類型攔截器
 @Override
public Object invoke(MethodInvocation mi) throws Throwable {
                //參數mi就是上面的this
		MethodInvocation oldInvocation = invocation.get();
                //ThreadLocal<MethodInvocation> invocation
                //線程暫存mi
		invocation.set(mi);
		try {
                        //遞歸上邊的proceed方法,到攔截器鏈下一個
			return mi.proceed();
		}
		finally {
                        //重置invocation
			invocation.set(oldInvocation);
		}
}

//AspectJAfterAdvice#invoke
//@After攔截器
public Object invoke(MethodInvocation mi) throws Throwable {
		try {
                         //遞歸下一個攔截器
			return mi.proceed();
		}
		finally {
                         //proceed()終止遞歸,出棧到此時執行finally
                         //因爲是finally,無論有無異常,@After必執行的
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
}

//AspectJAroundAdvice#invoke
//@Around攔截器+執行目標方法+終止遞歸+出棧
public Object invoke(MethodInvocation mi) throws Throwable {
		if (!(mi instanceof ProxyMethodInvocation)) {
			throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);
		}

                //將mi轉爲ProxyMethodInvocation
		ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;
                //取得JoinPoint
		ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);
                //取得匹配器
		JoinPointMatch jpm = getJoinPointMatch(pmi);
                //執行-->invokeAdviceMethodWithGivenArgs
		return invokeAdviceMethod(pjp, jpm, null, null);
}

//AbstractAspectJAdvice#invokeAdviceMethodWithGivenArgs
//@Around攔截器上面invokeAdviceMethod最終執行到此方法
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
		Object[] actualArgs = args;
                
		if (this.aspectJAdviceMethod.getParameterCount() == 0) {
			actualArgs = null;
		}
		try {
			ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
                        // aspectJAdviceMethod爲@Around註解的Method
                        // Method反射執行@Around切面方法
                        // 在切面中方法中調用joinPoint.proceed()
                        // 繼續遞歸proceed執行before方法+目標方法
			return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
                        //到此@Around切面方法+before方法+目標方法都已執行完成,return出棧
		}
		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();
		}
}



 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章