Spring-AOP源碼分析隨手記(一)

1.@EnableAspectJAutoProxy(proxyTargetClass = true)

就是弄了個"org.springframework.aop.config.internalAutoProxyCreator"::AnnotationAwareAspectJAutoProxyCreator.class的Bean到容器中

2.分析AnnotationAwareAspectJAutoProxyCreator.class類結構

得出了哪些是重要的幾個。

3.查看AnnotationAwareAspectJAutoProxyCreator源碼

=》查看父類AbstractAutoProxyCreator,有setBeanFactory等等各種繼承來的方法

4.又是一頓整理得出了一個圖(???)如下

pic1->AOP功能代碼分析圖

image

5.分析AbstractAutoProxyCreator。

setBeanFactory有個O標志被重寫了,打開,有個initBeanFactory方法,打開,創(chuàng)建了個advisorRetrievalHelper切面工具,又是O重寫 創(chuàng)建了aspectJAdvisorsBuilder

6.pic1圖里明顯看出有兩個關鍵性方法:

postProcessBeforeInstantiation和postProcessAfterInitialization

顯然是前后處理邏輯了??隙ㄏ瓤辞斑壿媝ostProcessBeforeInstantiation啊

7.postProcessBeforeInstantiation

斷點走起,居然是從這里進去的

image
image

所以這個之前分析IOC的createBean里的resolveBeforeInstantiation是AOP實現(xiàn)的關鍵。

8.分析postProcessBeforeInstantiation細節(jié)

8.1 isInfrastructureClass判斷是否基礎Bean

就是那種AOP本身的比如Advice、Pointcut、AopInfrastructureBean等,基礎的這種直接返回不需要代理

8.2 shouldSkip是否要跳過(包含找出切面)

8.2.1找出增強器(那種切面里的@After、@Before的方法)

跟隨斷點跳躍到之前setBeanFactory創(chuàng)建的advisorRetrievalHelper里去了幫忙實現(xiàn)的找增強器

實際上這里面又分兩部分了,一個是找事務的(findCandidateAdvisors)(本次斷點容器和緩存中都就沒用了直接返回空,不是事務,具體可以看aop源碼instan...圖)

另一部分是this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

image

跳進去看了下,它把所有的beanname拿出來找,去找切面類 找到了我寫的MyLogAspect

(打了切面切面注解)

然后找到了切面類,調用相關封裝的getAdvisors方法去拿增強器了。

其實就是獲取切面類的所有方法(getAdvisorMethods)把每個包含增強那些注解的方法包裝成Advice 放進緩存。

protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
   for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
      AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
      if (foundAnnotation != null) {
         return foundAnnotation;
      }
   }
   return null;
}

private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
      Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};

然后

switch (aspectJAnnotation.getAnnotationType()) {
   case AtPointcut:
      if (logger.isDebugEnabled()) {
         logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
      }
      return null;
   case AtAround:
      springAdvice = new AspectJAroundAdvice(
            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
   case AtBefore:
      springAdvice = new AspectJMethodBeforeAdvice(
            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
   case AtAfter:
      springAdvice = new AspectJAfterAdvice(
            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      break;
   case AtAfterReturning:
      springAdvice = new AspectJAfterReturningAdvice(
            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
      if (StringUtils.hasText(afterReturningAnnotation.returning())) {
         springAdvice.setReturningName(afterReturningAnnotation.returning());
      }
      break;
   case AtAfterThrowing:
      springAdvice = new AspectJAfterThrowingAdvice(
            candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
      AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
      if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
         springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
      }
      break;
   default:
      throw new UnsupportedOperationException(
            "Unsupported advice type on method: " + candidateAdviceMethod);
}

switch判斷注解類型 創(chuàng)建不同類型Advice 放進緩存

最終由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()找到了我寫的所有切面的增強方法

最終把整個切面類放到了advisorsCache的ConcurrentHashMap,以切面類的beanname作為key,增強器方法advice集合作為value

9.postProcessAfterInitialization

條件斷點,當beanname = "calculate"時停住。找出增強器后,看看后續(xù)aop是怎么和目標類結合的。

10.postProcessAfterInitialization細節(jié)

斷點已達。老辦法,看看是從哪調來的:

image
image

原來是這里,ioc創(chuàng)建完對象并給屬性賦完值之后。

回到postProcessAfterInitialization本身,就調了個wrapIfNecessary。邏輯都在里面了

10.1 找對應的增強器

打開斷點繼續(xù),先主要是個getAdvicesAndAdvisorsForBean然后調findEligibleAdvisors然后就是以前跑過的找事務略。然后主要是findAdvisorsThatCanApply(名字也看得出,它能用的 這個bean對應的切面),進去又是個canApply(candidate, clazz, hasIntroductions),這就是具體判斷了:

image
image

獲取所有方法,用匹配器match去匹配是否匹配上了

循環(huán)記下,全部找出來,找增強器就結束了!

10.2 織入生成代理對象

回到wrapIfNecessary開始創(chuàng)建代理對象了:

image
image

這里面框起來是涉及注解配置的,對應你配置的:

@EnableAspectJAutoProxy(exposeProxy = true)

@EnableAspectJAutoProxy(proxyTargetClass = true)

如果這兩個設置了的話,就會處理實現(xiàn)。

第二個是啟動優(yōu)先cglib,第一個是把代理對象創(chuàng)建好之后暴露出去,這樣就能讓原本this.dadd去調用方法本來不能增強的情況 可以用

((Calculate) AopContext.currentProxy()).add(numA,numB);也觸發(fā)增強效果

后面的話就是創(chuàng)建個代理工廠ProxyFactory,把增強器設置進去,最后調用getProxy

一路跳轉:

image

這就是最后網(wǎng)上背背背的東西了。在沒有接口和沒打優(yōu)先cglib的話用jdk創(chuàng)建否則cglib創(chuàng)建。

問題:

1.怎么得出來繼承結構哪些是重要的、哪些是不需要看不重要的

2.怎么整理出來的?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容