Spring AOP 筆記二(環(huán)繞通知,切面中獲取參數(shù))

此文是Sping in Action 第4版 英文原版切面部分的讀書筆記能曾,僅限交流使用嫁怀,有不足之處设捐,一定聽取修改。

系列目錄:
Spring AOP 筆記一(基礎(chǔ)概念塘淑,一個(gè)簡單切面)
Spring AOP 筆記二(環(huán)繞通知,切面中獲取參數(shù))
Spring AOP 筆記三(切面注解引入新的方法)

接上蚂斤,上一篇的示例切面中我們重復(fù)寫了三次代碼存捺。維護(hù)起來比較困難,可以在切面配置類中聲明一個(gè)切點(diǎn)方法曙蒸,相當(dāng)于聲明一個(gè)切面中的全局切點(diǎn)捌治。

1. 切點(diǎn)方法 代碼如下:

package concert;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class Audience {

    @Pointcut("execution(** concert.Performance.perform(..))")
    public void performance() {}
    
    @Before("performance()")
        public void silenceCellPhones() {
        System.out.println("Silencing cell phones");
    }
    @Before("performance()")
    public void takeSeats() {
        System.out.println("Taking seats");
    }
    @AfterReturning("performance()")
    public void applause() {
        System.out.println("CLAP CLAP CLAP!!!");
    }
    @AfterThrowing("performance()")
        public void demandRefund() {
        System.out.println("Demanding a refund");
    }
}
  • 切面方法即是使用 @Pointcut 注解的performance()方法。如何調(diào)用就在代碼中纽窟。

1.1 使用java方式進(jìn)行切面配置

上一篇文章已經(jīng)代碼貼出肖油,這里就回憶一下注解的意思:

  • @Configration:聲明當(dāng)前類是一個(gè)配置類。
  • @EnableAspectJAutoProxy 激活Spring對(duì)AspectJ的自動(dòng)代理功能的支持臂港。
  • @ComponentScan() 自動(dòng)掃描指定包名下所有使用@Service,@Component,@Repository,@Controller的類森枪,如果沒有指定包名,會(huì)默認(rèn)掃描類所在的包审孽。

2 創(chuàng)建環(huán)繞通知(around advice)

環(huán)繞通知相當(dāng)于after和before的合體县袱。

下面重寫Audience切面:

package concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class Audience {

    @Pointcut("execution(* com.memgxiang.concert.Performance.perform(..))")
    public void performance() {}
    
    @Around("performance()")
    public void watchPerformance(ProceedingJoinPoint jp) {
        try {
            System.out.println("手機(jī)靜音");
            System.out.println("得到座位");
            jp.proceed();
            System.out.println("鼓掌!!!");
        } catch (Throwable e) {
            System.out.println("這演的啥啊佑力!退票");
        }
    }
}

這里的 @Around注解就聲明了watchPerformance()方法成為了一個(gè)環(huán)繞通知切點(diǎn)式散。他的運(yùn)行結(jié)果與上例使用@Before,@After等等的效果相同〈虿可以發(fā)現(xiàn)watchPerformance()方法中給出了一個(gè)PreceedingJoinPoint類型的參數(shù)暴拄,這個(gè)是必須的,因?yàn)槟阈枰嬖V該切點(diǎn)中的任務(wù)相對(duì)與你的工作所處的位置编饺。使用ProceedingJoinPoint’s proceed()方法將你的任務(wù)放在你想要的位置乖篷。

3. 在通知中獲取參數(shù)。

在上面的@Around例子中反肋,watchPerformance()只有一個(gè)用于說明被切面的方法如何切入的參數(shù)那伐,而且這里的performance()方法中也沒有任何參數(shù),當(dāng)被切入的方法沒有參數(shù)的時(shí)候石蔗,可以使用上例中的那些簡單方式罕邀。
不過當(dāng)被切入(或者說被通知)的方法存在參數(shù)時(shí),我們想要在通知中獲取到該參數(shù)养距,就使用下面的方式诉探。
我對(duì)原書中的示例做了簡化。

首先定義一個(gè)類棍厌,有一個(gè)帶int類型參數(shù)的方法 playTrack() 肾胯,該方法就是將要被切入的方法竖席。


/**
 * 緊湊圓盤。
 * Created by Henvealf on 2016/8/28.
 */
public class CompactDisc {
    public void playTrack(int trackNumber){
        System.out.println("trackNumber =" + trackNumber);
    }
}

隨后就是定義一個(gè)切面:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
 *
 * Created by Henvealf on 2016/8/28.
 */
@Aspect
public class TrackCounter {

    @Pointcut("execution(* com.mengxiang.concert.CompactDisc.playTrack(int)) && args(trackNum)")
    public void trackPlayed(int trackNum) {}

    @Before("trackPlayed(trac)")
    public void countTrack(int trac) {
        System.out.println("我在切面中敬肚,我會(huì)在playTrack()運(yùn)行前被調(diào)用" + trac);
    }

}
  • 測(cè)試類在這里就不列出了毕荐。

這里我們用 @PointCut 注解了一個(gè)帶有int參數(shù)的方法 trackPlayed() ,將其定義為一個(gè)切點(diǎn)艳馒。在 @PointCut 中我們?nèi)テヅ?CompactDisc 類中的 playTrack() 方法憎亚,并且定制了其參數(shù)類型為int,這里當(dāng)這樣限制了被切入方法的類型弄慰,就必須同時(shí)使用 args() 標(biāo)識(shí)符來指明變量的名字,且名字要與定義切點(diǎn)的方法(trackPlayed)中的參數(shù)名字相比配第美。

之后在 countTrack()上使用@Before()來定義一個(gè)通知。里面直接使用了上面定義的切點(diǎn)方法陆爽,并且切點(diǎn)方法中加入了一個(gè)代表參數(shù)名的標(biāo)識(shí)trackNumber什往,此標(biāo)識(shí)與countTrack中的參數(shù)名必須相匹配。

從上面的例子可以發(fā)現(xiàn)慌闭,args()中的參數(shù)名標(biāo)識(shí)不需要與被通知的方法的參數(shù)名一致别威,它只是為了在切點(diǎn)內(nèi)部,互相區(qū)分參數(shù)列表中的各個(gè)參數(shù)贡必。

為了說明我們將被切入的類CompactDisc中的 playTrack 方法修改成具有兩個(gè)參數(shù):

    public void playTrack(int trackNumber,int number){
        System.out.println("trackNumber =" + trackNumber);
        System.out.println("number =" + number);
    }

隨之我們修改切點(diǎn)為:

@Pointcut("execution(* com.mengxiang.concert.CompactDisc.playTrack(int,int)) && args(trackNumb,numb))")
    public void trackPlayed(int trackNumb,int numb) {}
    
    
@Before("trackPlayed(trackNumber,number)")
public void countTrack(int trackNumber, int number) {
    System.out.println("我在切面中兔港,我會(huì)在playTrack()運(yùn)行前被調(diào)用" + trackNumber);
    System.out.println("我在切面中,我會(huì)在playTrack()運(yùn)行前被調(diào)用" + number);
}

注意@Pointcut中的 playTrack(int,int)args(trackNumb,numb)仔拟。

當(dāng)我們調(diào)用playTrack(20,40)后衫樊,發(fā)現(xiàn)輸出為:

我在切面中,我會(huì)在playTrack()運(yùn)行前被調(diào)用20
我在切面中利花,我會(huì)在playTrack()運(yùn)行前被調(diào)用40
trackNumber =22

現(xiàn)在我們將@Pointcut注解的trackPlayed()中的兩個(gè)參數(shù)調(diào)換科侈。即:

  • trackPlayed(int numb,int trackNumb){..}

會(huì)發(fā)現(xiàn)輸出結(jié)果出現(xiàn)了變化:

我在切面中,我會(huì)在playTrack()運(yùn)行前被調(diào)用40
我在切面中炒事,我會(huì)在playTrack()運(yùn)行前被調(diào)用20
trackNumber =22
number =40
  • 這樣大概就明白了臀栈。

本篇就結(jié)束了,有問題的同學(xué)評(píng)論告訴我挠乳,這個(gè)結(jié)束好生硬权薯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市睡扬,隨后出現(xiàn)的幾起案子盟蚣,更是在濱河造成了極大的恐慌,老刑警劉巖卖怜,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屎开,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡马靠,警方通過查閱死者的電腦和手機(jī)奄抽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門蔼两,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人逞度,你說我怎么就攤上這事额划。” “怎么了档泽?”我有些...
    開封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵锁孟,是天一觀的道長。 經(jīng)常有香客問我茁瘦,道長,這世上最難降的妖魔是什么储笑? 我笑而不...
    開封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任甜熔,我火速辦了婚禮,結(jié)果婚禮上突倍,老公的妹妹穿的比我還像新娘腔稀。我一直安慰自己,他們只是感情好羽历,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開白布焊虏。 她就那樣靜靜地躺著,像睡著了一般秕磷。 火紅的嫁衣襯著肌膚如雪诵闭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天澎嚣,我揣著相機(jī)與錄音疏尿,去河邊找鬼。 笑死易桃,一個(gè)胖子當(dāng)著我的面吹牛褥琐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播晤郑,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼敌呈,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了造寝?” 一聲冷哼從身側(cè)響起磕洪,我...
    開封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匹舞,沒想到半個(gè)月后褐鸥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叫榕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年晰绎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伶选。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尖昏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抽诉,到底是詐尸還是另有隱情,我是刑警寧澤河绽,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布唉窃,位于F島的核電站,受9級(jí)特大地震影響苟跪,放射性物質(zhì)發(fā)生泄漏矮嫉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一拨齐、第九天 我趴在偏房一處隱蔽的房頂上張望昨寞。 院中可真熱鬧,春花似錦歼狼、人聲如沸享怀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽值纱。三九已至坯汤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間疆偿,已是汗流浹背搓幌。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留反番,地道東北人叉钥。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓投队,卻偏偏與公主長得像爵川,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寝贡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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