日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

76 张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!

發(fā)布時間:2024/3/24 javascript 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 76 张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖! 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

下面我會簡單介紹一下 AOP 的基礎知識,以及使用方法,然后直接對源碼進行拆解。

不 BB,上文章目錄。

1. 基礎知識

1.1 什么是 AOP ?

AOP 的全稱是 “Aspect Oriented Programming”,即面向切面編程

在 AOP 的思想里面,周邊功能(比如性能統(tǒng)計,日志,事務管理等)被定義為切面,核心功能和切面功能分別獨立進行開發(fā),然后把核心功能和切面功能“編織”在一起,這就叫 AOP。

AOP 能夠?qū)⒛切┡c業(yè)務無關,卻為業(yè)務模塊所共同調(diào)用的邏輯封裝起來,便于減少系統(tǒng)的重復代碼,降低模塊間的耦合度,并有利于未來的可拓展性和可維護性。

1.2 AOP 基礎概念

  • 連接點(Join point):能夠被攔截的地方,Spring AOP 是基于動態(tài)代理的,所以是方法攔截的,每個成員方法都可以稱之為連接點;

  • 切點(Poincut):每個方法都可以稱之為連接點,我們具體定位到某一個方法就成為切點;

  • 增強/通知(Advice):表示添加到切點的一段邏輯代碼,并定位連接點的方位信息,簡單來說就定義了是干什么的,具體是在哪干;

  • 織入(Weaving):將增強/通知添加到目標類的具體連接點上的過程;

  • 引入/引介(Introduction):允許我們向現(xiàn)有的類添加新方法或?qū)傩?#xff0c;是一種特殊的增強;

  • 切面(Aspect):切面由切點和增強/通知組成,它既包括了橫切邏輯的定義、也包括了連接點的定義。

上面的解釋偏官方,下面用“方言”再給大家解釋一遍。

  • 切入點(Pointcut):在哪些類,哪些方法上切入(where);

  • 通知(Advice):在方法執(zhí)行的什么時機(when:方法前/方法后/方法前后)做什么(what:增強的功能);

  • 切面(Aspect):切面 = 切入點 + 通知,通俗點就是在什么時機,什么地方,做什么增強;

  • 織入(Weaving):把切面加入到對象,并創(chuàng)建出代理對象的過程,這個由 Spring 來完成。

5 種通知的分類:

  • 前置通知(Before Advice):在目標方法被調(diào)用前調(diào)用通知功能;

  • 后置通知(After Advice):在目標方法被調(diào)用之后調(diào)用通知功能;

  • 返回通知(After-returning):在目標方法成功執(zhí)行之后調(diào)用通知功能;

  • 異常通知(After-throwing):在目標方法拋出異常之后調(diào)用通知功能;

  • 環(huán)繞通知(Around):把整個目標方法包裹起來,在被調(diào)用前和調(diào)用之后分別調(diào)用通知功能。

1.3 AOP 簡單示例

新建 Louzai 類:

@Data @Service public?class?Louzai?{public?void?everyDay()?{System.out.println("睡覺");} }

添加 LouzaiAspect 切面:

@Aspect @Component public?class?LouzaiAspect?{@Pointcut("execution(*?com.java.Louzai.everyDay())")private?void?myPointCut()?{}//?前置通知@Before("myPointCut()")public?void?myBefore()?{System.out.println("吃飯");}//?后置通知@AfterReturning(value?=?"myPointCut()")public?void?myAfterReturning()?{System.out.println("打豆豆。。。");} }

applicationContext.xml 添加:

<!--啟用@Autowired等注解--> <context:annotation-config/> <context:component-scan?base-package="com"?/> <aop:aspectj-autoproxy?proxy-target-class="true"/>

程序入口:

public?class?MyTest?{public?static?void?main(String[]?args)?{ApplicationContext?context?=new?ClassPathXmlApplicationContext("classpath:applicationContext.xml");Louzai?louzai?=?(Louzai)?context.getBean("louzai");louzai.everyDay();} }

輸出:

吃飯 睡覺 打豆豆。。。

這個示例非常簡單,“睡覺” 加了前置和后置通知,但是 Spring 在內(nèi)部是如何工作的呢?

1.4 Spring AOP 工作流程

為了方便大家能更好看懂后面的源碼,我先整體介紹一下源碼的執(zhí)行流程,讓大家有一個整體的認識,否則容易被繞進去。

整個 Spring AOP 源碼,其實分為 3 塊,我們會結合上面的示例,給大家進行講解。

第一塊就是前置處理,我們在創(chuàng)建 Louzai Bean 的前置處理中,會遍歷程序所有的切面信息,然后將切面信息保存在緩存中,比如示例中 LouzaiAspect 的所有切面信息。

第二塊就是后置處理,我們在創(chuàng)建 Louzai Bean 的后置處理器中,里面會做兩件事情:

  • 獲取 Louzai 的切面方法:首先會從緩存中拿到所有的切面信息,和 Louzai 的所有方法進行匹配,然后找到 Louzai 所有需要進行 AOP 的方法。

  • 創(chuàng)建 AOP 代理對象:結合 Louzai 需要進行 AOP 的方法,選擇 Cglib 或 JDK,創(chuàng)建 AOP 代理對象。

第三塊就是執(zhí)行切面,通過“責任鏈 + 遞歸”,去執(zhí)行切面。

2. 源碼解讀

注意:Spring 的版本是 5.2.15.RELEASE,否則和我的代碼不一樣!!!

除了原理部分,上面的知識都不難,下面才是我們的重頭戲,讓你跟著樓仔,走一遍代碼流程。

2.1 代碼入口

這里需要多跑幾次,把前面的 beanName 跳過去,只看 louzai。

進入 doGetBean(),進入創(chuàng)建 Bean 的邏輯。

2.2 前置處理

主要就是遍歷切面,放入緩存。

這里是重點!敲黑板!!!

  • 我們會先遍歷所有的類;

  • 判斷是否切面,只有切面才會進入后面邏輯;

  • 獲取每個 Aspect 的切面列表;

  • 保存 Aspect 的切面列表到緩存 advisorsCache 中。

  • 到這里,獲取切面信息的流程就結束了,因為后續(xù)對切面數(shù)據(jù)的獲取,都是從緩存 advisorsCache 中拿到。

    下面就對上面的流程,再深入解讀一下。

    2.2.1 判斷是否是切面

    上圖的第 2 步,邏輯如下:

    2.2.2 獲取切面列表

    進入到 getAdvice(),生成切面信息。

    2.3 后置處理

    主要就是從緩存拿切面,和 louzai 的方法匹配,并創(chuàng)建 AOP 代理對象。

    進入 doCreateBean(),走下面邏輯。

    這里是重點!敲黑板!!!

  • 先獲取 louzai 類的所有切面列表;

  • 創(chuàng)建一個 AOP 的代理對象。

  • 2.3.1 獲取切面

    我們先進入第一步,看是如何獲取 louzai 的切面列表。

    進入 buildAspectJAdvisors(),這個方法應該有印象,就是前面將切面信息放入緩存 advisorsCache 中,現(xiàn)在這里就是要獲取緩存。

    再回到 findEligibleAdvisors(),從緩存拿到所有的切面信息后,繼續(xù)往后執(zhí)行。

    2.3.2 創(chuàng)建代理對象

    有了 louzai 的切面列表,后面就可以開始去創(chuàng)建 AOP 代理對象。

    這里是重點!敲黑板!!!

    這里有 2 種創(chuàng)建 AOP 代理對象的方式,我們是選用 Cglib 來創(chuàng)建。

    我們再回到創(chuàng)建代理對象的入口,看看創(chuàng)建的代理對象。

    2.4 切面執(zhí)行

    通過 “責任鏈 + 遞歸”,執(zhí)行切面和方法。

    前方高能!這塊邏輯非常復雜!!!

    下面就是“執(zhí)行切面”最核心的邏輯,簡單說一下設計思路:

  • 設計思路:采用遞歸 + 責任鏈的模式;

  • 遞歸:反復執(zhí)行 CglibMethodInvocation 的 proceed();

  • 退出遞歸條件:interceptorsAndDynamicMethodMatchers 數(shù)組中的對象,全部執(zhí)行完畢;

  • 責任鏈:示例中的責任鏈,是個長度為 3 的數(shù)組,每次取其中一個數(shù)組對象,然后去執(zhí)行對象的 invoke()。

  • 因為我們數(shù)組里面只有 3 個對象,所以只會遞歸 3 次,下面就看這 3 次是如何遞歸,責任鏈是如何執(zhí)行的,設計得很巧妙!

    2.4.1 第一次遞歸

    數(shù)組的第一個對象是 ExposeInvocationInterceptor,執(zhí)行 invoke(),注意入?yún)⑹?CglibMethodInvocation。

    里面啥都沒干,繼續(xù)執(zhí)行 CglibMethodInvocation 的 process()。

    2.4.2 第二次遞歸

    數(shù)組的第二個對象是 MethodBeforeAdviceInterceptor,執(zhí)行 invoke()。

    2.4.3 第三次遞歸

    數(shù)組的第二個對象是 AfterReturningAdviceInterceptor,執(zhí)行 invoke()。

    執(zhí)行完上面邏輯,就會退出遞歸,我們看看 invokeJoinpoint() 的執(zhí)行邏輯,其實就是執(zhí)行主方法。

    再回到第三次遞歸的入口,繼續(xù)執(zhí)行后面的切面。

    切面執(zhí)行邏輯,前面已經(jīng)演示過,直接看執(zhí)行方法。

    后面就依次退出遞歸,整個流程結束。

    2.4.4 設計思路

    這塊代碼,我研究了大半天,因為這個不是純粹的責任鏈模式。

    純粹的責任鏈模式,對象內(nèi)部有一個自身的 next 對象,執(zhí)行完當前對象的方法末尾,就會啟動 next 對象的執(zhí)行,直到最后一個 next 對象執(zhí)行完畢,或者中途因為某些條件中斷執(zhí)行,責任鏈才會退出。

    這里 CglibMethodInvocation 對象內(nèi)部沒有 next 對象,全程是通過 interceptorsAndDynamicMethodMatchers 長度為 3 的數(shù)組控制,依次去執(zhí)行數(shù)組中的對象,直到最后一個對象執(zhí)行完畢,責任鏈才會退出。

    這個也屬于責任鏈,只是實現(xiàn)方式不一樣,后面會詳細剖析,下面再討論一下,這些類之間的關系。

    我們的主對象是 CglibMethodInvocation,繼承于 ReflectiveMethodInvocation,然后 process() 的核心邏輯,其實都在 ReflectiveMethodInvocation 中。

    ReflectiveMethodInvocation 中的 process() 控制整個責任鏈的執(zhí)行。

    ReflectiveMethodInvocation 中的 process() 方法,里面有個長度為 3 的數(shù)組 interceptorsAndDynamicMethodMatchers,里面存儲了 3 個對象,分別為 ExposeInvocationInterceptor、MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor。

    注意!!!這 3 個對象,都是繼承 MethodInterceptor 接口。

    然后每次執(zhí)行 invoke() 時,里面都會去執(zhí)行 CglibMethodInvocation 的 process()。

    是不是聽得有些蒙圈?甭著急,我重新再幫你梳理一下。

    對象和方法的關系:

    • 接口繼承:數(shù)組中的 3 個對象,都是繼承 MethodInterceptor 接口,實現(xiàn)里面的 invoke() 方法;

    • 類繼承:我們的主對象 CglibMethodInvocation,繼承于 ReflectiveMethodInvocation,復用它的 process() 方法;

    • 兩者結合(策略模式):invoke() 的入?yún)?#xff0c;就是 CglibMethodInvocation,執(zhí)行 invoke() 時,內(nèi)部會執(zhí)行 CglibMethodInvocation.process(),這個其實就是個策略模式。

    可能有同學會說,invoke() 的入?yún)⑹?MethodInvocation,沒錯!但是 CglibMethodInvocation 也繼承了 MethodInvocation,不信自己可以去看。

    執(zhí)行邏輯:

    • 程序入口:是 CglibMethodInvocation 的 process() 方法;

    • 鏈式執(zhí)行(衍生的責任鏈模式):process() 中有個包含 3 個對象的數(shù)組,依次去執(zhí)行每個對象的 invoke() 方法。

    • 遞歸(邏輯回退):invoke() 方法會執(zhí)行切面邏輯,同時也會執(zhí)行 CglibMethodInvocation 的 process() 方法,讓邏輯再一次進入 process()。

    • 遞歸退出:當數(shù)字中的 3 個對象全部執(zhí)行完畢,流程結束。

    所以這里設計巧妙的地方,是因為純粹責任鏈模式,里面的 next 對象,需要保證里面的對象類型完全相同。

    但是數(shù)組里面的 3 個對象,里面沒有 next 成員對象,所以不能直接用責任鏈模式,那怎么辦呢?就單獨搞了一個 CglibMethodInvocation.process(),通過去無限遞歸 process(),來實現(xiàn)這個責任鏈的邏輯。

    這就是我們?yōu)槭裁匆丛创a,學習里面優(yōu)秀的設計思路!

    3. 總結

    我們再小節(jié)一下,文章先介紹了什么是 AOP,以及 AOP 的原理和示例。

    之后再剖析了 AOP 的源碼,分為 3 塊:

    • 將所有的切面都保存在緩存中;

    • 取出緩存中的切面列表,和 louzai 對象的所有方法匹配,拿到屬于 louzai 的切面列表;

    • 創(chuàng)建 AOP 代理對象;

    • 通過“責任鏈 + 遞歸”,去執(zhí)行切面邏輯。

    總結

    以上是生活随笔為你收集整理的76 张图,剖析 Spring AOP 源码,小白居然也能看懂,大神,请收下我的膝盖!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 久久久久久九九九九 | 无码精品国产一区二区三区 | 中文字幕第一页亚洲 | www.浪潮av.com | 卡通动漫亚洲综合 | 欧美一区二区在线播放 | 亚洲精品久久久久久无码色欲四季 | 亚洲精品成人 | 国产精品无码久久久久一区二区 | 在线黄网 | 日韩av三区 | 亚洲欧美激情在线 | 在线观看av的网站 | 久久久美女| 国产精品一二三四区 | 精品国产区| 青青草在线播放 | 日本妈妈9 | aaa人片在线 | 国产精品hd | 无码h肉动漫在线观看 | 天堂素人 | 李丽珍裸体午夜理伦片 | 天海翼一区二区 | 成人免费黄色网址 | 亚洲色图狠狠干 | 好吊色视频一区二区三区 | 日韩在线免费av | 极品91尤物被啪到呻吟喷水 | 精品欧美在线观看 | 中文字幕乱码亚洲精品一区 | 亚洲AV无码成人精品国产一区 | 日韩精品在线观看视频 | 黄色激情小说视频 | 久久三级视频 | 91在线看黄 | 女女同性女同一区二区三区按摩 | 色婷婷综合久久久久中文字幕 | 欧日韩精品 | 妞妞影视 | 一道本av在线 | 婷婷色中文字幕 | 久久久久五月 | 久久精品专区 | 欧美精品入口蜜桃 | 黄色三级视频网站 | 国产视频在线一区二区 | 国产精品观看 | 天天干天天综合 | 国产人妻久久精品一区二区三区 | 日日骚一区 | 怡红院一区二区三区 | 欧美性大战xxxxx久久久 | 性一区| 欧美激情在线观看一区 | 日韩av在线网 | 超碰日本 | 在线观看av一区 | 2019日韩中文字幕 | 国产av无码国产av毛片 | 夜夜精品一区二区无码 | 成人片免费视频 | 国产一区二区视频在线 | 97精品人妻一区二区三区蜜桃 | 中日韩黄色大片 | 国产做a | 激情国产| 在线超碰| 国产婷婷色 | 免费污片软件 | 欧美色综合| 色射射| 人妻夜夜爽天天爽 | 国产精品一区二区三区四 | 亚洲 欧美 激情 另类 校园 | 精品二区在线 | 国产一区二区三区福利 | 天天色亚洲 | 黄页网站免费观看 | www.亚洲综合 | 可以在线观看的av网站 | 男女搞黄网站 | 五月婷婷av | 免费在线视频一区二区 | 直接看av的网站 | 林雅儿欧洲留学恋爱日记在线 | 人妻无码一区二区三区久久99 | 欧美视频免费在线 | 欧美色国 | avt天堂网| 婷婷丁香激情 | 宅男在线视频 | 亚洲天堂性 | 日韩综合在线观看 | 伊人在线 | 亚洲欧美中文字幕5发布 | 天天成人| 色小姐综合网 | 高清乱码免费看污 |