成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從源碼入手,一文帶你讀懂Spring AOP面向切面編程

wawor4827 / 757人閱讀

摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。,織入,將作用在的過程。因?yàn)樵创a都是英文寫的。

之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》介紹了下JDK的動(dòng)態(tài)代理。

基于這兩者的實(shí)現(xiàn)上,這次來探索下Spring的AOP原理。雖然AOP是基于Spring容器和動(dòng)態(tài)代理,但不了解這兩者原理也絲毫不影響理解AOP的原理實(shí)現(xiàn),因?yàn)榇蠹移鸫a都會(huì)用。

AOP,Aspect Oriented Programming,面向切面編程。在很多時(shí)候我們寫一些功能的時(shí)候,不需要用到繼承這么重的方法,例如對(duì)每個(gè)方法在執(zhí)行前打log,在沒有AOP的情況下,我們只能對(duì)每個(gè)方法都寫一句打log的語句。如果是一個(gè)復(fù)雜點(diǎn)的功能,那么將會(huì)產(chǎn)生許多重復(fù)的代碼,而且會(huì)對(duì)模塊之間有更多的耦合。
然而,在AOP下,我們只需要通過特定的方法,就能直接切入代碼,添加自定義的功能(后續(xù)再講AOP里面的概念點(diǎn))。

下面將從一個(gè)簡(jiǎn)單的示例入手,拆解示例的內(nèi)容,通過源碼分析,一步步帶大家讀懂AOP的原理實(shí)現(xiàn)。

使用示例

以下代碼不以文字形式展示,若需要代碼,可以到github查看完整Demo。
Demo:https://github.com/Zack-Ku/sp...

Spring項(xiàng)目依然是用xml最原始的配置方式,為了只是能簡(jiǎn)單地閱讀原理,否則會(huì)多很多自動(dòng)配置的內(nèi)容在里面。而AOP的配置用的是注解形式,因?yàn)楫吘箍雌饋懋吘骨逦?,容易理解邏輯?/p>

創(chuàng)建一個(gè)Gradle項(xiàng)目,添加對(duì)應(yīng)的Spring與AOP的依賴。
(Gradle和Maven類似,都是自動(dòng)化構(gòu)建的工具。但與Maven相比,Gradle是基于groovy,采用DSL格式,具有更強(qiáng)的靈活性、簡(jiǎn)潔性、拓展性。現(xiàn)在連Spring的官方源碼都是用Gradle的,可以說是一款面向未來的工具,后續(xù)也值得我們深入學(xué)習(xí)。)

創(chuàng)建一個(gè)Bean,TestBean。

創(chuàng)建AOP的Aspect。

然后寫一個(gè)啟動(dòng)類,測(cè)試以上配置

運(yùn)行結(jié)果:

com.zack.demo.TestBean.getStr()開始執(zhí)行...
getStr():Testing!
com.zack.demo.TestBean.getStr()方法結(jié)束...

Demo:https://github.com/Zack-Ku/sp...

示例解析與AOP術(shù)語概念

看到上面的結(jié)果,很容易猜想到,LogAspect作用了在TestBean上,使得每次執(zhí)行TestBean上的方法時(shí),都會(huì)執(zhí)行對(duì)應(yīng)的方法(before/after)。

LogAspect中帶注解@Pointcut的allMethod(),是用來掃描程序中的連接點(diǎn)。當(dāng)執(zhí)行一個(gè)方法時(shí),命中了連接點(diǎn),則會(huì)根據(jù)不同的通知,執(zhí)行對(duì)應(yīng)的織入代碼。在上面例子中,執(zhí)行g(shù)etStr()前會(huì)執(zhí)行LogAspect中的before(),執(zhí)行g(shù)etStr()后會(huì)執(zhí)行LogAspect中的after()。

具體的通知包含

@Before,前置通知,執(zhí)行方法前執(zhí)行

@AfterReturn,返回通知,正常返回方法后執(zhí)行

@After,后置通知,方法最終結(jié)束后執(zhí)行,相當(dāng)于finaly

@Around,環(huán)繞通知,圍繞整個(gè)方法

@AfterThrowing,異常通知,拋出異常后執(zhí)行

開發(fā)者在命中連接點(diǎn)時(shí),可以通過以上不同的通知,執(zhí)行對(duì)應(yīng)方法。這就是AOP中的Advisor。

以上的內(nèi)容其實(shí)已經(jīng)把AOP核心的概念都已經(jīng)點(diǎn)出來了,我們?cè)偕钊刖唧w的認(rèn)識(shí)下其中的術(shù)語,

Aspect,切面,一個(gè)關(guān)注點(diǎn)的模塊。
例子中,LogAspect就是切面。

JoinPoint, 連接點(diǎn),程序執(zhí)行中的某個(gè)點(diǎn),某個(gè)位置。
例子中,testBean.getStr()是連接點(diǎn)。

PointCut,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。
例子中,@PointCut注解就是切點(diǎn)表達(dá)式,匹配對(duì)應(yīng)的連接點(diǎn)

Advice,通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動(dòng)作。
例子中,before()與after()方法中的代碼。

TargetObject,目標(biāo)對(duì)象,指被切入的對(duì)象。
例子中,從ctx中取出的testBean則是目標(biāo)對(duì)象。

Weave,織入,將Advice作用在JoinPoint的過程。

以上概念看起來可以還比較難懂,可以通過以下一圖(來源于網(wǎng)絡(luò))來理解

請(qǐng)各位讀者和各位程序員,在閱讀源碼的時(shí)候,一定要先搞清楚基本概念,和一定一定要知道對(duì)應(yīng)概念的英文,否則在看源碼的時(shí)候,根本對(duì)不上號(hào),使理解難度大大提高。因?yàn)樵创a都是英文寫的。

至此AOP的基本使用和概念相信大家都有一定的了解,下面開始從源碼入手,去探索整個(gè)Spring AOP的實(shí)現(xiàn)。

源碼分析

上面的例子之所以能完成AOP的代理,只因?yàn)镾pring的xml配置里面加了這一句

< aop : aspectj-autoproxy / >

加上了這一個(gè)配置,使得整個(gè)Spring項(xiàng)目擁有了AOP的功能。全局搜索下aspectj-autoproxy這個(gè)字段,可以發(fā)現(xiàn),是這個(gè)類AspectJAutoProxyBeanDefinitionParser解析了這個(gè)元素。

其中的parse方法調(diào)用的是AopNamespaceUtils類中的registerAspectJAnnotationAutoProxyCreatorIfNecessary。這個(gè)方法作用是初始化一個(gè)AOP專用的Bean,并且注冊(cè)到Spring容器中。

解析這三個(gè)操作,

第一句,注冊(cè)一個(gè)AnnotationAwareAspectJAutoProxyCreator(稱它為自動(dòng)代理器),這個(gè)Creator是AOP的操作核心,也是掃描Bean,代理Bean的操作所在。

第二句,解析配置元素,決定代理的模式。其中有JDK動(dòng)態(tài)代理,還有CGLIB代理,這部分后續(xù)會(huì)再細(xì)講。

第三句,作為系統(tǒng)組件,把Creator這個(gè)Bean,放到Spring容器中。讓Spring實(shí)例化,啟動(dòng)這個(gè)Creator。

自動(dòng)代理器

下面我們來細(xì)看AnnotationAwareAspectJAutoProxyCreator是怎么對(duì)Bean做AOP的。

AnnotationAwareAspectJAutoProxyCreator的父類AbstractAutoProxyCreator,里面實(shí)現(xiàn)了BeanPostProceesor接口的postProcessAfterInitialization方法(該方法在一個(gè)Bean加載到Spring后會(huì)執(zhí)行)。

關(guān)聯(lián)注釋描述可知,當(dāng)一個(gè)bean加載完后,執(zhí)行了該方法,會(huì)生成一個(gè)新的代理對(duì)象,返回context中加載。

下面重點(diǎn)看其中的wrapIfNecessary方法。講述了整個(gè)AOP的核心流程,是Spring AOP最最最核心的代碼所在。

看到紅框的兩個(gè)核心方法,可以知道,先從剛加載的Bean中掃描出所有的advice和advisor,然后用它來創(chuàng)建一個(gè)代理對(duì)象。

獲取Advisor

先看如何掃描出advice和advisor。
一步步Debug getAdvicesAndAdvisorsForBean(),找到BeanFactoryAspectJAdvisorsBuilder中的buildAspectJAdvisors方法。

該方法就是找出Spring容器中存在的AspectBean,然后返回所有AspectBean中的Advisor。

示例中,LogAspect就是AspectBean,然后LogAspect中的before和after方法就是Advisor。
所以最終返回了LogAspect中的Advisor(before和after)。

創(chuàng)建代理

拿到了所有的Advisor后,就進(jìn)入了創(chuàng)建代理的流程了createProxy()。

這些入?yún)?,?duì)比上一篇講過的動(dòng)態(tài)代理,其實(shí)非常相似。

beanClass,加載到Spring,觸發(fā)AOP的bean類

targetSource,目標(biāo)對(duì)象,示例中則是從ctx中取出的testBean

specificInterceptors,指定Advisor,示例中則是before和after的方法。

下面來具體看下代理的過程

代碼可以概括為,創(chuàng)建一個(gè)proxyFactory對(duì)象,然后把上面的參數(shù)都丟到這個(gè)這個(gè)工廠里,最后從proxyFactory獲取一個(gè)代理對(duì)象。

來看看ProxyFactory的getProxy方法是怎么生成代理對(duì)象的。

Debug該方法,可以在DefaultAopProxyFactory中createAopProxy看到

工廠會(huì)根據(jù)配置與目標(biāo)對(duì)象的類型,選擇用JDK動(dòng)態(tài)代理(參考《你真的完全了解Java動(dòng)態(tài)代理嗎?看這篇就夠了》)還是CGLIB的代理(CGLIB具體在后續(xù)講)。

代理后的對(duì)象放回ctx中,然后當(dāng)程序執(zhí)行的時(shí)候,會(huì)直接調(diào)用這個(gè)代理類。

至此整個(gè)AOP的代理流程就結(jié)束了。下面來了解下CGLIG代理與JDK代理的不同

CGLIB與JDK代理區(qū)別

CGLIB(Code Generation Library)是一個(gè)強(qiáng)大的,高性能,高質(zhì)量的Code生成類庫(kù)。它可以在運(yùn)行期擴(kuò)展Java類與實(shí)現(xiàn)Java接口。Hibernate支持它來實(shí)現(xiàn)PO(Persistent Object 持久化對(duì)象)字節(jié)碼的動(dòng)態(tài)生成。

回顧下JDK代理,JDK代理需要一組需要實(shí)現(xiàn)的接口,然后通過這些接口獲取構(gòu)造方法,用這個(gè)構(gòu)造方法和InvocationHandler,實(shí)例化一個(gè)對(duì)象出來。所以JDK的方式是基于接口的。

而CGLIB的代理是基于類的,用目標(biāo)類生成一個(gè)子類,子類重寫父類的方法,從而達(dá)到動(dòng)態(tài)代理的效果。CGLIB的使用和實(shí)現(xiàn)等后面有機(jī)會(huì)再詳細(xì)介紹。目前暫時(shí)只要理解兩者不同的使用場(chǎng)景就足夠了。

總結(jié)

回顧下Spring AOP的流程

Spring加載自動(dòng)代理器AnnotationAwareAspectJAutoProxyCreator,當(dāng)作一個(gè)系統(tǒng)組件。

當(dāng)一個(gè)bean加載到Spring中時(shí),會(huì)觸發(fā)自動(dòng)代理器中的bean后置處理

bean后置處理,會(huì)先掃描bean中所有的Advisor

然后用這些Adviosr和其他參數(shù)構(gòu)建ProxyFactory

ProxyFactory會(huì)根據(jù)配置和目標(biāo)對(duì)象的類型尋找代理的方式(JDK動(dòng)態(tài)代理或CGLIG代理)

然后代理出來的對(duì)象放回context中,完成Spring AOP代理

相信大家通過閱讀本文,對(duì)Spring的AOP處理有一定的認(rèn)識(shí)。想更深入地了解,探索每一步,每一行代碼的實(shí)現(xiàn),可以下載Demo源碼,一步步地調(diào)試
Demo:https://github.com/Zack-Ku/sp...

更多技術(shù)文章、精彩干貨,請(qǐng)關(guān)注
博客:zackku.com
微信公眾號(hào):Zack說碼

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77133.html

相關(guān)文章

  • “過時(shí)”的SpringMVC我們到底在用什么?深入分析DispatchServlet源碼

    摘要:?jiǎn)栴}來了,我們到底還在用嗎答案是,不全用。后者是初始化的配置,主要是的配置。啟動(dòng)類測(cè)試啟動(dòng)項(xiàng)目后,在瀏覽器里面輸入。通過查詢已裝載的,并且支持該而獲取的。按照前面對(duì)的描述,對(duì)于而言,這個(gè)必定是。的核心在的方法中。 之前已經(jīng)分析過了Spring的IOC(《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》)與AOP(《從源碼入手,一文帶你讀懂Spring AOP面向切面編程》)的源碼,本次...

    array_huang 評(píng)論0 收藏0
  • 【推薦】最新200篇:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    BicycleWarrior 評(píng)論0 收藏0
  • 【推薦】最新200篇:技術(shù)文章整理

    摘要:作為面試官,我是如何甄別應(yīng)聘者的包裝程度語言和等其他語言的對(duì)比分析和主從復(fù)制的原理詳解和持久化的原理是什么面試中經(jīng)常被問到的持久化與恢復(fù)實(shí)現(xiàn)故障恢復(fù)自動(dòng)化詳解哨兵技術(shù)查漏補(bǔ)缺最易錯(cuò)過的技術(shù)要點(diǎn)大掃盲意外宕機(jī)不難解決,但你真的懂?dāng)?shù)據(jù)恢復(fù)嗎每秒 作為面試官,我是如何甄別應(yīng)聘者的包裝程度Go語言和Java、python等其他語言的對(duì)比分析 Redis和MySQL Redis:主從復(fù)制的原理詳...

    tommego 評(píng)論0 收藏0
  • 墻裂推薦:搜云庫(kù)技術(shù)團(tuán)隊(duì),面試必備的技術(shù)干貨

    摘要:今天整理了一下近大半年以來的一些文章,和我的預(yù)期一樣,很多文章我都忘記自己曾經(jīng)寫過了,這個(gè)記錄的過程讓我也有了新的理解。希望大家,收藏,點(diǎn)贊,加轉(zhuǎn)發(fā)。 今天整理了一下近大半年以來的一些文章,和我的預(yù)期一樣,很多文章我都忘記自己曾經(jīng)寫過了,這個(gè)記錄的過程讓我也有了新的理解。希望大家,收藏,點(diǎn)贊,加轉(zhuǎn)發(fā)。 面試必備 面試必備:深入Spring MVC DispatchServlet 源碼...

    SegmentFault 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<