溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring AOP設(shè)計(jì)思想與原理是什么

發(fā)布時(shí)間:2022-01-18 09:27:08 來源:億速云 閱讀:93 作者:柒染 欄目:大數(shù)據(jù)

這篇文章主要為大家分析了Spring AOP設(shè)計(jì)思想與原理是什么的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì)易懂,操作細(xì)節(jié)合理,具有一定參考價(jià)值。如果感興趣的話,不妨跟著跟隨小編一起來看看,下面跟著小編一起深入學(xué)習(xí)“Spring AOP設(shè)計(jì)思想與原理是什么”的知識(shí)吧。

前言

Spring 提供了AOP(Aspect Oriented Programming) 的支持, 那么,什么是AOP呢?本文將通過一個(gè)另外一個(gè)角度來詮釋AOP的概念,幫助你更好地理解和使用Spring AOP。

1. Java程序運(yùn)行在JVM中的特征

當(dāng)我們?cè)谀硞€(gè)類Foo中寫好了一個(gè)main()方法,然后執(zhí)行java Foo,你的Java程序之旅就開啟了,如下:

Spring AOP設(shè)計(jì)思想與原理是什么

那么在這個(gè)執(zhí)行的過程中,JVM都為你干了什么呢?

當(dāng)你執(zhí)行java Foo 的時(shí)候,JVM會(huì)創(chuàng)建一個(gè)主線程main,這個(gè)主線程以上述的main()方法作為入口,開始執(zhí)行你的代碼。每一個(gè)線程在內(nèi)存中都會(huì)維護(hù)一個(gè)屬于自己的棧(Stack),記錄著整個(gè)程序執(zhí)行的過程。棧里的每一個(gè)元素稱為棧幀(Stack Frame),棧幀表示著某個(gè)方法調(diào)用,會(huì)記錄方法調(diào)用的信息;實(shí)際上我們?cè)诖a中調(diào)用一個(gè)方法的時(shí)候,在內(nèi)存中就對(duì)應(yīng)著一個(gè)棧幀的入棧和出棧。

在某個(gè)特定的時(shí)間點(diǎn),一個(gè)Main線程內(nèi)的棧會(huì)呈現(xiàn)如下圖所示的情況:

Spring AOP設(shè)計(jì)思想與原理是什么

從線程棧的角度來看,我們可以看到,JVM處理Java程序的基本單位是方法調(diào)用。實(shí)際上,JVM執(zhí)行的最基本單位的指令(即原子操作)是匯編語言性質(zhì)的機(jī)器字節(jié)碼。這里之所以講方法調(diào)用時(shí)Java程序的基本執(zhí)行單位,是從更宏觀的角度看待的。

如何獲取到虛擬機(jī)線程棧中的內(nèi)容(即方法調(diào)用過程)?

試想一下,如何能夠獲取到JVM線程棧中的方法調(diào)用的內(nèi)容? 我相信所有的Java programmer都知道這個(gè)答案。Java Programmer幾乎每天都能看到它------當(dāng)我們的代碼拋出異常而未捕獲或者運(yùn)行時(shí)出現(xiàn)了Error錯(cuò)誤時(shí),我們會(huì)受到一個(gè)非常討厭的Log信息,如下:

Spring AOP設(shè)計(jì)思想與原理是什么

當(dāng)然,除了代碼拋出異常外,我們還是可以其他方式察覺JVM線程棧內(nèi)的內(nèi)容??梢酝ㄟ^Thread.dumpStack()方法創(chuàng)建一個(gè)假的Exception實(shí)例,然后將這個(gè)Exception實(shí)例記錄的當(dāng)前線程棧的內(nèi)容輸出到標(biāo)準(zhǔn)錯(cuò)誤流中。例如我在某處代碼里執(zhí)行了Thread.dumpStack()方法,輸出了如下的結(jié)果:

Spring AOP設(shè)計(jì)思想與原理是什么

2.  Java程序執(zhí)行流 【了解AOP、連接點(diǎn)(Join Point)、切入點(diǎn)(point cut)   的概念 】

如果從虛擬機(jī)線程棧的角度考慮Java程序執(zhí)行的話,那么,你會(huì)發(fā)現(xiàn),真?zhèn)€程序運(yùn)行的過程就是方法調(diào)用的過程。我們按照方法執(zhí)行的順序,將方法調(diào)用排成一串,這樣就構(gòu)成了Java程序流。

我們將上述的線程棧里的方法調(diào)用按照?qǐng)?zhí)行流排列,會(huì)有如下類似的圖:

Spring AOP設(shè)計(jì)思想與原理是什么

基于時(shí)間序列,我們可以將方法調(diào)用排成一條線。而每個(gè)方法調(diào)用則可以看成Java執(zhí)行流中的一個(gè)節(jié)點(diǎn)。這個(gè)節(jié)點(diǎn)在AOP的術(shù)語中,被稱為Join Point,即連接點(diǎn)。 一個(gè)Java程序的運(yùn)行的過程,就是若干個(gè)連接點(diǎn)連接起來依次執(zhí)行的過程。

在我們正常的面向?qū)ο蟮乃季S中, 我們考慮的是如何按照時(shí)間序列通過方法調(diào)用來實(shí)現(xiàn)我們的業(yè)務(wù)邏輯。那么,什么是AOP(即面向切面的編程)呢?

通常面向?qū)ο蟮某绦?,代碼都是按照時(shí)間序列縱向展開的,而他們都有一個(gè)共性:即都是已方法調(diào)用作為基本執(zhí)行單位展開的。 將方法調(diào)用當(dāng)做一個(gè)連接點(diǎn),那么由連接點(diǎn)串起來的程序執(zhí)行流就是整個(gè)程序的執(zhí)行過程。

AOP(Aspect Oriented Programming)則是從另外一個(gè)角度來考慮整個(gè)程序的,AOP將每一個(gè)方法調(diào)用,即連接點(diǎn)作為編程的入口,針對(duì)方法調(diào)用進(jìn)行編程。從執(zhí)行的邏輯上來看,相當(dāng)于在之前縱向的按照時(shí)間軸執(zhí)行的程序橫向切入。相當(dāng)于將之前的程序橫向切割成若干的面,即Aspect.每個(gè)面被稱為切面。

所以,根據(jù)我的理解,AOP本質(zhì)上是針對(duì)方法調(diào)用的編程思路。

Spring AOP設(shè)計(jì)思想與原理是什么

既然AOP是針對(duì)切面進(jìn)行的編程的,那么,你需要選擇哪些切面(即 連接點(diǎn)Joint Point)作為你的編程對(duì)象呢?

因?yàn)榍忻姹举|(zhì)上是每一個(gè)方法調(diào)用,選擇切面的過程實(shí)際上就是選擇方法的過程。那么,被選擇的切面(Aspect)在AOP術(shù)語里被稱為切入點(diǎn)(Point Cut).  切入點(diǎn)實(shí)際上也是從所有的連接點(diǎn)(Join point)挑選自己感興趣的連接點(diǎn)的過程。

Spring AOP設(shè)計(jì)思想與原理是什么

Spring AOP框架中通過 方法匹配表達(dá)式來表示切入點(diǎn)(Point Cut),至于詳細(xì)的表達(dá)式語法是什么 不是本文的重點(diǎn),請(qǐng)讀者自行參考Spring相應(yīng)的說明文檔。

既然AOP是針對(duì)方法調(diào)用(連接點(diǎn))的編程, 現(xiàn)在又選取了你感興趣的自己感興趣的鏈接點(diǎn)---切入點(diǎn)(Point Cut)了,那么,AOP能對(duì)它做什么類型的編程呢?AOP能做什么呢? 

了解這個(gè)之前,我們先要知道一個(gè)非常重要的問題: 既然AOP是對(duì)方法調(diào)用進(jìn)行的編程,那么,AOP如何捕獲方法調(diào)用的呢? 弄清楚這個(gè)問題,你不得不了解設(shè)計(jì)模式中的代理模式了。下面我們先來了解一下引入了代理模式的Java程序執(zhí)行流是什么樣子的。

3.    引入了代理模式的Java程序執(zhí)行流(AOP實(shí)現(xiàn)的機(jī)制)

我們假設(shè)在我們的Java代碼里,都為實(shí)例對(duì)象通過代理模式創(chuàng)建了代理對(duì)象,訪問這些實(shí)例對(duì)象必須要通過代理,那么,加入了proxy對(duì)象的Java程序執(zhí)行流會(huì)變得稍微復(fù)雜起來。

我們來看下加入了proxy對(duì)象后,Java程序執(zhí)行流的示意圖:

Spring AOP設(shè)計(jì)思想與原理是什么

由上圖可以看出,只要想調(diào)用某一個(gè)實(shí)例對(duì)象的方法時(shí),都會(huì)經(jīng)過這個(gè)實(shí)例對(duì)象相對(duì)應(yīng)的代理對(duì)象, 即執(zhí)行的控制權(quán)先交給代理對(duì)象。

關(guān)于代理模式

代理模式屬于Java代碼中經(jīng)常用到的、也是比較重要的設(shè)計(jì)模式。代理模式可以為某些對(duì)象除了實(shí)現(xiàn)本身的功能外,提供一些額外的功能,大致作用如下圖所示:

Spring AOP設(shè)計(jì)思想與原理是什么

加入了代理模式的Java程序執(zhí)行流,使得所有的方法調(diào)用都經(jīng)過了代理對(duì)象。對(duì)于Spring AOP框架而言,它負(fù)責(zé)控制著真?zhèn)€容器內(nèi)部的代理對(duì)象。當(dāng)我們調(diào)用了某一個(gè)實(shí)例對(duì)象的任何一個(gè)非final的public方法時(shí),整個(gè)Spring框架都會(huì)知曉。

此時(shí)的SpringAOP框架在某種程度上扮演著一個(gè)上帝的角色:它知道你在這個(gè)框架內(nèi)所做的任何操作,你對(duì)每一個(gè)實(shí)例對(duì)象的非final的public方法調(diào)用都可以被框架察覺到!

Spring AOP設(shè)計(jì)思想與原理是什么

既然Spring代理層可以察覺到你所做的每一次對(duì)實(shí)例對(duì)象的方法調(diào)用,那么,Spring就有機(jī)會(huì)在這個(gè)代理的過程中插入Spring的自己的業(yè)務(wù)代碼。

4.     Spring AOP的工作原理

前面已經(jīng)介紹了AOP編程首先要選擇它感興趣的連接點(diǎn)----即切入點(diǎn)(Point cut),那么,AOP能對(duì)切入點(diǎn)做什么樣的編程呢? 我們先將代理模式下的某個(gè)連接點(diǎn)細(xì)化,你會(huì)看到如下這個(gè)示意圖所表示的過程:

Spring AOP設(shè)計(jì)思想與原理是什么

為了降低我們對(duì)Spring的AOP的理解難度,我在這里將代理角色的職能進(jìn)行了簡(jiǎn)化,方便大家理解。(注意:真實(shí)的Spring AOP的proxy角色扮演的只能比這復(fù)雜的多,這里只是簡(jiǎn)化,方便大家理解,請(qǐng)不要先入為主)代理模式的代理角色最起碼要考慮三個(gè)階段:

1.調(diào)用真正對(duì)象的方法之前,應(yīng)該需要做什么?

2. 在調(diào)用真正對(duì)象的方法過程中,如果拋出了異常,需要做什么?

3.在調(diào)用真正對(duì)象的方法后,返回了結(jié)果了,需要做什么?

AOP對(duì)這個(gè)方法調(diào)用的編程,就是針對(duì)這三個(gè)階段插入自己的業(yè)務(wù)代碼。

現(xiàn)在我們假設(shè)當(dāng)前RealSubject這個(gè)角色的類是 org.luanlouis.springlearning.aop.FooService,當(dāng)前這個(gè)連接點(diǎn)對(duì)應(yīng)的方法簽名是:public void foo()。那么上述的代理對(duì)象的三個(gè)階段將會(huì)有以下的處理邏輯:            

1. 在調(diào)用真正對(duì)象的方法之前,

proxy會(huì)告訴Spring AOP:  "我將要調(diào)用類org.luanlouis.springlearning.aop.FooService  的public void foo(),在調(diào)用之前,你有什么處理建議嗎?";

Spring AOP這時(shí)根據(jù)proxy提供的類名和方法簽名,然后拿這些信息嘗試匹配是否在其感興趣的切入點(diǎn)內(nèi),如果在感興趣的切入點(diǎn)內(nèi),Spring AOP會(huì)返回 MethodBeforeAdvice處理建議,告訴proxy應(yīng)該執(zhí)行的操作;

2. 在調(diào)用真正對(duì)象的方法過程中,如果拋出了異常,需要做什么?

proxy告訴Spring AOP: “我調(diào)用類org.luanlouis.springlearning.aop.FooService  的public void foo()過程中拋出了異常,你有什么處理建議?”

Spring AOP根據(jù)proxy提供的類型和方法簽名,確定了在其感興趣的切入點(diǎn)內(nèi),則返回相應(yīng)的處理建議ThrowsAdvice,告訴proxy這個(gè)時(shí)期應(yīng)該采取的操作。

3.在調(diào)用真正對(duì)象的方法后,返回了結(jié)果了,需要做什么?

proxy告訴Spring AOP:"我調(diào)用類org.luanlouis.springlearning.aop.FooService  的public void foo()結(jié)束了,并返回了結(jié)果你現(xiàn)在有什么處理建議?";

Spring AOP 根據(jù)proxy提供的類型名和方法簽名,確定了在其感興趣的切入點(diǎn)內(nèi),則返回AfterReturingAdivce處理建議,proxy得到這個(gè)處理建議,然后執(zhí)行建議;

Spring AOP設(shè)計(jì)思想與原理是什么

上述的示意圖中已經(jīng)明確表明了Spring AOP應(yīng)該做什么樣的工作:根據(jù)proxy提供的特定類的特定方法執(zhí)行的特定時(shí)期階段給出相應(yīng)的處理建議。要完成該工作,Spring AOP應(yīng)該實(shí)現(xiàn):

1.確定自己對(duì)什么類的什么方法感興趣? -----即確定 AOP的切入點(diǎn)(Point Cut),這個(gè)可以通過切入點(diǎn)(Point Cut)表達(dá)式來完成;

2. 對(duì)應(yīng)的的類的方法的執(zhí)行特定時(shí)期給出什么處理建議?------這個(gè)需要Spring AOP提供相應(yīng)的建議 ,即我們常說的Advice。

Spring AOP設(shè)計(jì)思想與原理是什么

關(guān)于“Spring AOP設(shè)計(jì)思想與原理是什么”就介紹到這了,更多相關(guān)內(nèi)容可以搜索億速云以前的文章,希望能夠幫助大家答疑解惑,請(qǐng)多多支持億速云網(wǎng)站!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI