什么是面向切面編程AOP槽驶?

Spring AOP是Spring的三大基石之一
它究竟解決了什么痛點(diǎn)能獲如此殊榮握侧?
Java在面向?qū)ο蟮氖澜缋餆o限風(fēng)光蚯瞧,oop成就了無數(shù)經(jīng)典的軟件嘿期,它讓我們的軟件更健壯品擎,更易于維護(hù),但是程序猿對軟件的質(zhì)量追求是永無止境的备徐,oop對于業(yè)務(wù)的抽象和封裝完美的無懈可擊然而對于系統(tǒng)層面的一些需求比如系統(tǒng)日志萄传,性能統(tǒng)計(jì)等,分散在軟件的各個角落蜜猾,維護(hù)起來很是不爽秀菱,這種問題的解決確是oop力所不能及的,于是AOP橫空出世先來看一個簡單的小例子蹭睡,體會一下AOP能解決什么問題:如果我們要在A,B,C三個類的do方法中都加入日志功能定義一個日志類Record衍菱,加日志的方法:addRecord

Public class A{
 Public void do(){
 …
 Record.addRecord();//添加日志
 }
}

Public class B{
 Public void do(){
 …
 Record.addRecord();//添加日志
 }
}
Public class C{
 Public void do(){
 …
 Record.addRecord();//添加日志
 }
}

這樣做可以解決問題,但是總感覺有些別扭肩豁,每個類的do方法中都調(diào)用了添加日志的方法脊串,添加日志的方法不是我們的核心業(yè)務(wù),我們卻要去處理它隨著系統(tǒng)越來越完善清钥,類似這樣的非核心業(yè)務(wù)也會越來越多琼锋,比如權(quán)限,異常處理祟昭,性能監(jiān)控等這樣的功能出現(xiàn)在很多類的很多方法中干擾了我們的核心業(yè)務(wù)代碼缕坎,怎么解決呢?AOP就是為此而生:看看AOP是如何解決的篡悟?


圖片.png

從上圖可以看出對于日志記錄谜叹,性能監(jiān)控匾寝,異常處理這樣的非核心功能,單獨(dú)被抽取出來荷腊,與業(yè)務(wù)代碼分離旗吁,橫切在核心業(yè)務(wù)代碼之上

這就是我們通常所說的面向切面編程(AOP),通過一個例子看看他是如何實(shí)現(xiàn)的

創(chuàng)建一個UserDao類:

@Repository
public class UserDao {
 public void addUser(){
 System.out.println("添加用戶");
 }
 public void updateUser(){
 System.out.println("修改用戶");
 }
 public void deleteUser(){
 System.out.println("刪除用戶");
 }
}

創(chuàng)建一個切面類:

@Aspect
public class MyAspectLog {
    /**
     * 方法執(zhí)行完后執(zhí)行的方法
     */
@After(value="execution(* cn.xh.dao.UserDao.addUser(..))")
    public void log(){
        System.out.println("記錄日志");
    }
}
在spring配置文件中加入:
<!-- 啟動@aspectj的自動代理支持-->
    <aop:aspectj-autoproxy />
 
    <!-- 定義aspect類 -->
    <bean name="myAspect" class="cn.xh.dao. MyAspectLog "/>

當(dāng)我們創(chuàng)建UserDao的對象userDao調(diào)用addUser方法的時候會打印“添加用戶”,“記錄日志”很神奇吧,究竟發(fā)生了什么停局?明明addUser方法里面只有打印”添加用戶”啊這就是Spring AOP的強(qiáng)大之處很钓,在運(yùn)行時通過動態(tài)代理技術(shù)對UserDao的addUser方法進(jìn)行了增強(qiáng),添加了記錄日志的功能董栽。動態(tài)代理其實(shí)就是在運(yùn)行時動態(tài)的生成目標(biāo)對象的代理對象码倦,在代理對象中對目標(biāo)對象的方法進(jìn)行增強(qiáng),關(guān)于動態(tài)代理技術(shù)我會在另一篇文章中詳細(xì)介紹锭碳,現(xiàn)在先來看一下AOP中幾個重要的概念:
一:通知:就是會在目標(biāo)方法執(zhí)行前后執(zhí)行的方法

上面這個例子中:

@After(value="execution(* cn.xh.dao.UserDao.addUser(..))")
 public void log(){
 System.out.println("記錄日志");
 }

這個方法就是通知袁稽,目標(biāo)方法是UserDao類的addUser(),在addUser執(zhí)行之后執(zhí)行了log方法,所以log方法是后置通知擒抛,通過在方法上加上@After注解來表示推汽。通過通知和目標(biāo)方法的執(zhí)行順序我們可以把通知分為五種:前置通知(before):在目標(biāo)方法執(zhí)行之前執(zhí)行。后置通知(after):在目標(biāo)方法執(zhí)行之后執(zhí)行后置返回通知(after returning):在目標(biāo)方法返回之后執(zhí)行歧沪,先執(zhí)行后置通知再執(zhí)行后置返回通知歹撒。這三種通知的執(zhí)行順序如下:

try{
    try{
        //@Before
        method.invoke(..);
    }finally{
        //@After
    }
    //@AfterReturning
}catch(){
    //@AfterThrowing
}

異常通知(after throwing):在目標(biāo)方法拋出異常時執(zhí)行環(huán)繞通知(around):在目標(biāo)函數(shù)執(zhí)行中執(zhí)行二:切入點(diǎn):應(yīng)用通知進(jìn)行增強(qiáng)的目標(biāo)方法現(xiàn)在面臨的問題是如何去描述這個需要被增強(qiáng)的目標(biāo)方法,如果只是一個具體的方法需要增強(qiáng)那簡單诊胞,通過類名和方法名找到它就可以了暖夭,但是往往真實(shí)的需求中很多方法需要同樣的通知進(jìn)行增強(qiáng),Spring AOP為我們提供了一個描述方法的語法比如上例中的:

@After(value="execution(* cn.xh.dao.UserDao.addUser(..))")execution(* cn.xh.dao.UserDao.addUser(..)就是用來描述需要應(yīng)用通知的方法的撵孤。這里的含義是cn.xh.dao包UserDao類中的參數(shù)任意迈着,返回值任意的addUser方法。

關(guān)于這種描述更多具體的寫法我會在另一篇文章中詳述邪码。

三:連接點(diǎn):連接點(diǎn)就是可以應(yīng)用通知進(jìn)行增強(qiáng)的方法

因?yàn)镾pring Aop只能針對方法進(jìn)行增強(qiáng)裕菠,所以這里的連接點(diǎn)指的就是方法,一旦連接點(diǎn)被增強(qiáng)闭专,它就成為了切入點(diǎn)奴潘。

如上例中的:

public void addUser(){
 System.out.println("添加用戶");
 }
 public void updateUser(){
 System.out.println("修改用戶");
 }
 public void deleteUser(){
 System.out.println("刪除用戶");
 }
三個方法都是連接點(diǎn)。

四:切面:是切入點(diǎn)和通知的結(jié)合

可以用切面類來表示:

@Aspect
public class MyAspectLog {
    /**
     * 方法執(zhí)行完后執(zhí)行的方法
     */
@After(value="execution(* cn.xh.dao.UserDao.addUser(..))")
    public void log(){
        System.out.println("記錄日志");
    }
}

在這個類中既包含了切入點(diǎn)addUser又包含了通知:log().

五:織入:就是通過動態(tài)代理對目標(biāo)對象方法進(jìn)行增強(qiáng)的過程喻圃。

轉(zhuǎn)自:https://www.zhihu.com/question/24863332/answer/863736101

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萤彩,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子斧拍,更是在濱河造成了極大的恐慌雀扶,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愚墓,居然都是意外死亡予权,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門浪册,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扫腺,“玉大人,你說我怎么就攤上這事村象“驶罚” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵厚者,是天一觀的道長躁劣。 經(jīng)常有香客問我,道長库菲,這世上最難降的妖魔是什么账忘? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮熙宇,結(jié)果婚禮上鳖擒,老公的妹妹穿的比我還像新娘。我一直安慰自己烫止,他們只是感情好蒋荚,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著烈拒,像睡著了一般圆裕。 火紅的嫁衣襯著肌膚如雪广鳍。 梳的紋絲不亂的頭發(fā)上荆几,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音赊时,去河邊找鬼吨铸。 笑死,一個胖子當(dāng)著我的面吹牛祖秒,可吹牛的內(nèi)容都是我干的诞吱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼竭缝,長吁一口氣:“原來是場噩夢啊……” “哼房维!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抬纸,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咙俩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阿趁,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膜蛔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了脖阵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片皂股。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖命黔,靈堂內(nèi)的尸體忽然破棺而出呜呐,到底是詐尸還是另有隱情,我是刑警寧澤悍募,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布卵史,位于F島的核電站,受9級特大地震影響搜立,放射性物質(zhì)發(fā)生泄漏以躯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一啄踊、第九天 我趴在偏房一處隱蔽的房頂上張望忧设。 院中可真熱鬧,春花似錦颠通、人聲如沸址晕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谨垃。三九已至,卻和暖如春硼控,著一層夾襖步出監(jiān)牢的瞬間刘陶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工牢撼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匙隔,地道東北人。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓熏版,卻偏偏與公主長得像纷责,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子撼短,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容