Spring學(xué)習(xí)手冊(cè)(10)—— Spring AOP配置

Spring學(xué)習(xí)手冊(cè)(9)—— Spring AOP入門(mén)講述了AOP技術(shù)以及AOP基本概念蔫仙,最后我們了解了Spring對(duì)AOP的支持鸵赫。本文我們將以XML配置的方式來(lái)學(xué)習(xí)Spring AOP的具體使用荧止。

一、引入aop模式

如果想使用XML的方式配置AOP信息煮寡,我們需要先在XML配置文件中引入aop模式(aop schema)流强,因此我們的XML配置文件頭頭信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> 
        <!-- bean definitions here -->
</beans>

這樣配之后,我們就可以在xml文件里面直接引用aop標(biāo)簽了贮尖。

二笛粘、定義一個(gè)切面

一個(gè)Spring AOP的切面(Aspect)在xml中也是一個(gè)傳統(tǒng)的bean,而使用標(biāo)簽<aop:aspect>定義一個(gè)切面湿硝,并且使用ref來(lái)執(zhí)行被定義為該切面的bean薪前。

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        ...
    </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
    ...
</bean>

如上,我們定義了一個(gè)id為aBean的bean實(shí)例关斜,然后使用<aop:aspect>標(biāo)簽定義了一個(gè)id為myAspect的切面示括,而該切面指向aBean。

三痢畜、定義一個(gè)切點(diǎn)(pointcut)

上篇我們說(shuō)過(guò)垛膝,切點(diǎn)表達(dá)式用于匹配連接點(diǎn)(join point),然后根據(jù)配置的增強(qiáng)(Advice)方法在連接點(diǎn)運(yùn)行時(shí)選擇合適時(shí)間執(zhí)行丁稀。因?yàn)镾pring AOP目前僅支持運(yùn)行方法類(lèi)型的連接點(diǎn)吼拥,所以也可以認(rèn)為與一個(gè)切點(diǎn)匹配一個(gè)bean的執(zhí)行方法。

一個(gè)切點(diǎn)包含兩部分:

  • 包含方法和名字的簽名线衫;
  • 切點(diǎn)表達(dá)式:用于匹配具體的方法

因此我們使用xml定義切點(diǎn)如下所示:

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        <aop:pointcut id="businessService"
            expression="execution(* com.xyz.myapp.service.*.*(..))"/>
        ...
    </aop:aspect>
</aop:config>

<aop:pointcut>必須在<aop:aspect>內(nèi)部使用定義切點(diǎn)凿可,使用expression的值指明切點(diǎn)表達(dá)式,id為該切點(diǎn)定義類(lèi)唯一標(biāo)示方便配置引用桶雀。這里并沒(méi)有定義切點(diǎn)(pointcut) 簽名,切點(diǎn)簽名定義一般在使用@AspectJ注解方式定義切點(diǎn)時(shí)定義唬复。下面我們著重說(shuō)明下切點(diǎn)表達(dá)式的語(yǔ)法情況矗积。

支持的切點(diǎn)(pointcut)標(biāo)示

Spring AOP 支持以下AspectJ 的切點(diǎn)標(biāo)示(AspectJ pointcut designators)簡(jiǎn)稱(chēng)PCD,由于Spring AOP并沒(méi)有全部支持所有的PCD敞咧,因此若使用了不存在該列表內(nèi)的標(biāo)示則會(huì)拋出異常棘捣。

標(biāo)簽名 說(shuō)明
execution 匹配運(yùn)行方法的連接點(diǎn)
within 使匹配連接點(diǎn)限定在特定類(lèi)型
this 限定匹配的連接點(diǎn)是給定類(lèi)型的實(shí)例
target 限定匹配連接點(diǎn)的目標(biāo)是給定類(lèi)型的實(shí)例
args 限定連接點(diǎn)的參數(shù)是給定類(lèi)型的實(shí)例
@target 限定匹配的連接點(diǎn)的運(yùn)行的對(duì)象有該類(lèi)型的注解
@args 運(yùn)行時(shí)傳遞的參數(shù)擁有給定類(lèi)型的注解
@within 限定匹配給定指定注解類(lèi)型的連接點(diǎn)
@annotation 限定連接點(diǎn)擁有指定的注解
bean 使得連接點(diǎn)匹配特質(zhì)的bean或bean集合

Tip:我們可以使用&&||休建、乍恐!來(lái)將連接點(diǎn)表達(dá)式關(guān)聯(lián)起來(lái)评疗。
然而在XML配置中該類(lèi)字符需要轉(zhuǎn)換,因此我們可以使用更語(yǔ)義化的句子符號(hào)and茵烈、or百匆、not

例子

使用execution例子

 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
        throws-pattern?)

以上除ret-type-pattern呜投、name-pattern加匈、param-pattern為必須外,其他皆為可選仑荐。

  • 匹配所有的公有方法
    execution(public * *(..))
  • 匹配所有以set開(kāi)頭的方法
    execution(* set*(..))
  • 匹配所有AccountService接口定義的方法
    execution(* com.xyz.service.AccountService.*(..))
  • 匹配所有service包內(nèi)的方法
    execution(* com.xyz.service..(..))
  • 匹配所有service包以及子包內(nèi)的方法
    execution(* com.xyz.service...(..))
  • 所有在service包內(nèi)的連接點(diǎn)
    within(com.xyz.service.*)
  • 所有service包以及子包內(nèi)的連接點(diǎn)
    within(com.xyz.service..*)
  • 所有實(shí)現(xiàn)AccountService接口的連接點(diǎn)
    this(com.xyz.service.AccountService)
  • 所有的目標(biāo)對(duì)象實(shí)現(xiàn)AccountService接口的連接點(diǎn)
    target(com.xyz.service.AccountService)
  • 有一個(gè)參數(shù)并且運(yùn)行時(shí)傳入?yún)?shù)為Serializable的連接點(diǎn)
    args(java.io.Serializable)
  • 目標(biāo)對(duì)象有@Transactional注解
    @target(org.springframework.transaction.annotation.Transactional)
  • 定義的目標(biāo)對(duì)象類(lèi)型含有@Transactional注解
    @within(org.springframework.transaction.annotation.Transactional)
  • 含有@Transactional注解的可運(yùn)行方法
    @annotation(org.springframework.transaction.annotation.Transactional)
  • 含有一個(gè)參數(shù)并且在運(yùn)行時(shí)傳入的參數(shù)含有@Classified注解
    @args(com.xyz.security.Classified)
  • bean名字定義為tradeService的連接點(diǎn)
    bean(tradeService)
  • bean名字滿足Service命名的所有連接點(diǎn)
    bean(
    Service)

四雕拼、定義增強(qiáng)方法(Advice)

Before advice
<aop:aspect id="beforeExample" ref="aBean">
    <aop:pointcut id="dataAccessOperation"
            expression="execution(* com.xyz.myapp.dao.*.*(..))"/>
    
    <aop:before
        pointcut-ref="dataAccessOperation"
        method="doAccessCheck"/>

    ...

</aop:aspect>

<aop:before>使用pointcut-ref引用一個(gè)切點(diǎn),并且指定增強(qiáng)執(zhí)行方法為doAccessCheck粘招。值的注意的是名為aBean的bean(也就是我們定義的切面)必須實(shí)現(xiàn)doAccessCheck方法啥寇。該方法會(huì)在目標(biāo)方法執(zhí)行前執(zhí)行。

After returning advice
<aop:aspect id="afterReturningExample" ref="aBean">
    <aop:pointcut id="dataAccessOperation"
            expression="execution(* com.xyz.myapp.dao.*.*(..))"/>
    <aop:after-returning
        pointcut-ref="dataAccessOperation"
        method="doAccessCheck"/>

    ...
</aop:aspect>

同上洒扎,該方法會(huì)在切點(diǎn)執(zhí)行正常返回后執(zhí)行辑甜。
當(dāng)然如果你需要獲取返回對(duì)象的話,你需要將配置信息改為如下所示:

<aop:aspect id="afterReturningExample" ref="aBean">
    ...
    <aop:after-returning
        pointcut-ref="dataAccessOperation"
        returning="retVal"
        method="doAccessCheck"/>

    ...

</aop:aspect>

其中doAccessCheck方法定義如下,其中參數(shù)名必須與XML里面配置相同逊笆,也就是說(shuō)必須與XML中的retVal一致栈戳。

public void doAccessCheck(Object retVal) {...}
After throwing advice
<aop:aspect id="afterThrowingExample" ref="aBean">
    ...
    <aop:after-throwing
        pointcut-ref="dataAccessOperation"
        method="doRecoveryActions"/>

    ...

</aop:aspect>

當(dāng)然如果需要獲取拋出的異常時(shí)我們可以如下配置:

<aop:aspect id="afterThrowingExample" ref="aBean">

    <aop:after-throwing
        pointcut-ref="dataAccessOperation"
        throwing="dataAccessEx"
        method="doRecoveryActions"/>

    ...

</aop:aspect>

其中doRecoveryActions方法定義如下且必須有名為dataAccessEx參數(shù):

public void doRecoveryActions(DataAccessException dataAccessEx) {...}
After (finally) advice

切點(diǎn)返回后執(zhí)行如下增強(qiáng)方法(無(wú)論正常返回還是異常退出):

<aop:aspect id="afterFinallyExample" ref="aBean">

    <aop:after
        pointcut-ref="dataAccessOperation"
        method="doReleaseLock"/>

    ...

</aop:aspect>
Around advice 環(huán)繞增強(qiáng)方法

該類(lèi)型的Advice環(huán)繞著連接點(diǎn),該增強(qiáng)方法可以選擇調(diào)用或者不掉用連接點(diǎn)方法难裆。

<aop:aspect id="aroundExample" ref="aBean">

    <aop:around
        pointcut-ref="businessService"
        method="doBasicProfiling"/>

    ...

</aop:aspect>
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
}

如上所示子檀,我們使用aop:around來(lái)定義環(huán)繞增強(qiáng),方法定義的第一個(gè)參數(shù)必須為ProceedingJoinPoint類(lèi)乃戈,在Around增強(qiáng)方法中褂痰,需要調(diào)用processed方法才會(huì)執(zhí)行真正的切點(diǎn)方法,否則則會(huì)放棄執(zhí)行切點(diǎn)方法症虑。

Advice 參數(shù)

有時(shí)我們需要獲取到目標(biāo)方法的參數(shù)信息缩歪,而Spring AOP為我們提供了方便的獲取方式,接下來(lái)我們就來(lái)了解下如何通過(guò)XML配置來(lái)獲取目標(biāo)方法的參數(shù)信息谍憔。
我們定義如下代碼

package com.aop.learn.service;

public interface StudentQueryService {

    /**
     * 根據(jù)姓名和年齡查詢(xún)學(xué)生信息匪蝙,
     * 假設(shè)無(wú)重復(fù)現(xiàn)象
    */
    Student  queryStdent(String name,int age);
    
    //...
}
package com.aop.learn.service.impl;
public class StudentQueryServiceImpl implements StudentQueryService {
    public Student queryStdent(String name, int age) {

        // do something 
        // query database or create a new object 
    }
}

切面例子(攔截器)

package com.aop.learn.interceptor;
public class InterceptorSample {

    public Object interceptorMethod(ProceedingJoinPoint call, String name, int age) throws Throwable {
          // do something
          Object result =  call.proceed();
        //do something
    }
}

配置信息如下

<!--定義bean信息-->
<bean id="aspectSample",class="com.aop.learn.interceptor.InterceptorSample">
<!--配置切面信息-->
<aop:config>
        <aop:aspect ref="aspectSample">

            <aop:pointcut id="pointsample"
                expression="execution(* com.aop.learn.service.StudentQueryService.queryStdent(..))
                and args(name, age)"/>
            <aop:around pointcut-ref="pointsample"
                method="interceptorMethod"/>
        </aop:aspect>
    </aop:config>

如上配置信息,在expression語(yǔ)句中增加了args(name,age),該表達(dá)式定義了變量名為name和age的參數(shù)习贫,該參數(shù)名必須和增強(qiáng)方法中名字一致逛球,這樣我們就能在增強(qiáng)方法中獲取目標(biāo)方法的參數(shù)信息了。

五苫昌、總結(jié)

本文我們主要學(xué)習(xí)了如何使用XML配置方式來(lái)完成Spring AOP的使用颤绕。文章中我們學(xué)習(xí)了很多配置標(biāo)簽,完成了切面定義、切點(diǎn)定義以及多種增強(qiáng)方法的定義奥务。至此我們已經(jīng)掌握了Spring AOP的基本知識(shí)點(diǎn)物独,可在具體的項(xiàng)目開(kāi)發(fā)中使用。不過(guò)學(xué)了那么多的知識(shí)點(diǎn)氯葬,我們還是需要一定的實(shí)踐來(lái)進(jìn)行消化吸收挡篓。接下來(lái)我們將構(gòu)造例子用來(lái)鞏固學(xué)習(xí)到的知識(shí)點(diǎn)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溢谤,一起剝皮案震驚了整個(gè)濱河市瞻凤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌世杀,老刑警劉巖阀参,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瞻坝,居然都是意外死亡蛛壳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)所刀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)衙荐,“玉大人,你說(shuō)我怎么就攤上這事浮创∮且鳎” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵斩披,是天一觀的道長(zhǎng)溜族。 經(jīng)常有香客問(wèn)我,道長(zhǎng)垦沉,這世上最難降的妖魔是什么煌抒? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮厕倍,結(jié)果婚禮上寡壮,老公的妹妹穿的比我還像新娘。我一直安慰自己讹弯,他們只是感情好况既,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著组民,像睡著了一般棒仍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邪乍,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天降狠,我揣著相機(jī)與錄音,去河邊找鬼庇楞。 笑死榜配,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吕晌。 我是一名探鬼主播蛋褥,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼睛驳!你這毒婦竟也來(lái)了烙心?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乏沸,失蹤者是張志新(化名)和其女友劉穎淫茵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蹬跃,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匙瘪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蝶缀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丹喻。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖翁都,靈堂內(nèi)的尸體忽然破棺而出碍论,到底是詐尸還是另有隱情,我是刑警寧澤柄慰,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布鳍悠,位于F島的核電站,受9級(jí)特大地震影響先煎,放射性物質(zhì)發(fā)生泄漏贼涩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一薯蝎、第九天 我趴在偏房一處隱蔽的房頂上張望遥倦。 院中可真熱鬧,春花似錦占锯、人聲如沸袒哥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)堡称。三九已至,卻和暖如春艺演,著一層夾襖步出監(jiān)牢的瞬間却紧,已是汗流浹背桐臊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晓殊,地道東北人断凶。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像巫俺,于是被迫代替她去往敵國(guó)和親认烁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理介汹,服務(wù)發(fā)現(xiàn)却嗡,斷路器,智...
    卡卡羅2017閱讀 134,659評(píng)論 18 139
  • 本博中關(guān)于spring的文章:Spring IOC和AOP原理嘹承,Spring事務(wù)原理探究窗价,Spring配置文件屬性...
    Maggie編程去閱讀 4,104評(píng)論 0 34
  • 基本知識(shí) 其實(shí), 接觸了這么久的 AOP, 我感覺(jué), AOP 給人難以理解的一個(gè)關(guān)鍵點(diǎn)是它的概念比較多, 而且坑爹...
    永順閱讀 8,209評(píng)論 5 114
  • 我不知道自己為什么心情不好,真不知道叹卷,好煩哦舌镶!我都不知道自己咋個(gè)了,哎豪娜!為什么會(huì)覺(jué)得現(xiàn)在只剩下我一個(gè)了呢餐胀!我肯定有...
    youlilian258閱讀 165評(píng)論 0 0
  • 1.問(wèn)題 請(qǐng)求后臺(tái)驗(yàn)證碼接口否灾,獲取驗(yàn)證碼和驗(yàn)證碼校驗(yàn)的接口,校驗(yàn)時(shí)總是獲取不到數(shù)值鸣奔,就是兩次的SESSIONID不...
    ZZES_ZCDC閱讀 5,433評(píng)論 0 0