spring詳解(十)「AOP」

當相同的切面里的兩個增強處理需要在相同的連接點被織入時畏吓,Spring AOP將以隨機的方式來織入這兩個增強處理,沒有辦法指定他們的順序,如果一定要它們以特定的順序被織入,則可以考慮把它們壓縮到一個增強處理中莱睁,或者是把它們分別放在不同的切面,在通過切面的優(yōu)先等級來排序

如果只要訪問目標方法的參數(shù),Spring還提供了一個更加簡單的方式:我們可以在程序中使用args來綁定目標方法的參數(shù),如果args表達是中指定一個或多個參數(shù),則該切入點只匹配具有對應形參的方法芒澜,且目標方法的參數(shù)值將被出入增強處理方法仰剿。
如:

@Aspect
publicclass AccessArgsAspect {
    @AfterReturning(pointcut ="execution(* cn.hb.spring.service1.*.*(..))"
    +"&&args(food,time)", returning ="retValue")
    publicvoid access(String food, Date time, Object retValue) {
        System.out.println("目標方法中的String參數(shù)" + food);
        System.out.println("目標方法的time參數(shù)" + time);
        System.out.println("模擬日志記錄功能......");
        System.out.println("目標參數(shù)的返回值:"+retValue);
    }
}
@Component
publicclass Chinese3implements Person2 {
    @Override
    public String sayHello(String word) {
        return word;
    }
    publicvoid eat(String food, Date time) {
        System.out.println("我正在吃:" + food+",現(xiàn)在的時間是:" + time);
    }
}

為什么目標方法的返回值是null,因為該切入點只匹配 public void eat(String food, Date time)方法痴晦。
從上面可以得出南吮,使用args表達式有如下兩個作用:
--提供更簡單的方式訪問目標方法的參數(shù);
--可用于對切入表達式增加額外限制誊酌。
除此之外部凑,使用args表達式時還可以使用如下形式:args(name,age,..),這表明增強處理方法中可通過name碧浊,age來訪問目標方法的參數(shù)涂邀,上面表達式括號中的2點,它表示可匹配更多的參數(shù)辉词,如:
public void doSomething(String name,int age)
這意味著只要目標方法第一個參數(shù)是String類型必孤,第二個參數(shù)是int則該方法就可以匹配該切入點猾骡。


定義切入點

正如前面的FourAdviceTest程序中看到的瑞躺,這個切面類定義了4個增強處理,這4個增強處理分別指定了相同的切入點表達式兴想,這種做法顯然不符合軟件設計的原則:我們將那個切入點表達式重復了4次幢哨,如果需要該這個切入點,那么就要修改4處嫂便。

Spring AOP只支持以Spring Bean的方法執(zhí)行組作為連接點.

例如:

@Pointcut("execution(* transfer(..))")
private void anyOldTransfer(){}

一旦采用上面的代碼片段定義了名為anyOldTrandser的切入點之后捞镰,程序就可以重復使用該切入點了,甚至可以在其他切面類毙替、其他包的切面類里使用該切入點岸售,不過這取決于該方法簽名前的訪問修飾符。


切入點指示符

正如前面的execution就是一個切入點指示符厂画,Spring AOP僅僅支持部分AspectJ切入點指示符凸丸,不僅如此Spring AOP只支持使用方法調(diào)用作為連接點,所以Spring AOP的切入點指示符僅匹配方法執(zhí)行的連接點袱院。

Spring AOP一共支持如下幾種切入點指示符:

execution:用于匹配執(zhí)行方法的連接點屎慢,是Spring AOP最主要的切入點指示符瞭稼,execution表達式的格式如下:

execution(modifies-pattern?  ret-type-pattern  declaring-type-parttern?  name--pattern(parm-pattern)  throws-pattern?)

以上打了問號的都可以省略。

上面格式中的execution是不變的腻惠,用于作為execution表達式的開頭环肘,整個表示式各個部分的解釋為:

modifies-pattern:指定方法的修飾符,支持通配符集灌,該部分可以省略悔雹。

ret-type-pattern:指定方法的返回值類型,支持通配符欣喧,可以使用“*”通配符來匹配所有返回值類型荠商。

declaring-type-parttern:指定方法所屬的類,支持通配符续誉,該部分可以省略莱没。

name--pattern:指定匹配指定方法名,支持通配符酷鸦,可以使用“*”通配符來匹配所有方法饰躲。

parm-pattern:指定方法聲明中的形參列表,支持兩個通配符:“”臼隔、“..”嘹裂,其中表示一個任意類型的參數(shù),而“..”表示零個或多個任意類型的參數(shù)摔握。

throws-pattern:指定方法聲明拋出的異常寄狼,支持通配符,該部分可以省略氨淌。

例如下面幾個execution表達式:

//匹配任意public方法的執(zhí)行泊愧。
execution(public * * (..))
//匹配任意方法名以set開始的方法。
execution(* set* (..))
//匹配AccountService里定義的任意方法的執(zhí)行盛正。
execution(* org.hb.AccountService.* (..))
//匹配Service包中任意類的任意方法的執(zhí)行删咱。
execution(* org.hb.service.*.*(..))

within:限定匹配特定類型的連接點,當使用Spring AOP的時候豪筝,只能匹配方法執(zhí)行的連接點,例如下面幾個within表達式:

//在Service包中的任意連接點痰滋。
within(* org,hb.service.*)
//在Service包或者子包的任意連接點
within(* org.hb.service..*)

this:用于限定AOP代理必須指定類型的實例,用于匹配該對象的所有連接點续崖。當使用Spring AOP的時候敲街,只能匹配方法執(zhí)行的連接點
例如:

//匹配實現(xiàn)了AccountService接口的代理對象的所有連接點
this(org.hb.service.AccountService)

target:用于限定目標對象必須是指定類型的實例,用于匹配該對象的所有連接點严望,當使用Spring AOP只匹配執(zhí)行方法的連接點多艇。例如:

//匹配實現(xiàn)了AccountService接口的目標對象的所有連接點
target(org.hb.service.AccountService)

args:用于對連接點的參數(shù)類型進行限制,要求參數(shù)類型是指定類型的實例著蟹,例如:

//匹配只接受一個參數(shù)墩蔓,且傳入的參數(shù)類型是Serializable的所有連接點
args(java.io.Serializable)

注意:該例中給出的切入點表達式與execution(* *(java.io.Serializable))不同:args版本只匹配動態(tài)運行時傳入?yún)?shù)值是Serializable類型的情況梢莽,而execution版本只匹配方法簽名只包含一個Serializable類型的參數(shù)的方法。

bean:用于指定只匹配指定Bean實例內(nèi)連接點奸披,實際上只能使用方法執(zhí)行作為連接點昏名,定義bean表達式需要傳入id或name,表示只匹配Bean實例內(nèi)連接點阵面,支持“*”通配符轻局。
例如:

/匹配tradeService Bean實例內(nèi)方法執(zhí)行的連接點
bean(tradeService)
//匹配名字以Service結(jié)尾的Bean實例內(nèi)方法執(zhí)行的連接點。
bean(*Service)

組合切入點表達式
Spring支持3中邏輯運算符來組合切入點表達式:
&&:要求連接點同時匹配兩個切入點表達式样刷;
||:只要連接點匹配任意一個切入點表達式仑扑;
!:要求連接點不匹配指定切入點表達式置鼻。


AOP 基于配置Xml文件的管理方式

除了前面介紹的基于JDK1.5的Annotation方式來定義切面镇饮、切入點和增強處理,Spring AOP也允許使用XML文件來定義管理它們箕母。

實際上储藐,使用XML定義AOP也是@AspectJ一樣的同樣需要指定相關數(shù)據(jù):配置切面、切入點嘶是、增強處理所需要的信息完全一樣钙勃,只是提供這些信息的位置不一樣而已。使用XMLA文件配置AOPd的方式有很多優(yōu)點但是也有一些缺點:

xml配置方式比@AspectJ方式有更多的限制:僅支持“singleton”切面的Bean聂喇,不能在xml中組合多個命名連接點的聲明辖源。

在Spring的配置文件中,所有的切面希太、切入點和增強處理都必須定義在<aop:config../>元素內(nèi)部克饶。<beans../>元素下可以包含多個<aop:config../>元素。

一個<aop:config../>可以包含多個pointcut跛十、advisor和aspect元素彤路,且這3個元素必須按照此順序類定義秕硝。

注意:當我們使用<aop:config../>方式進行配置時芥映,可能與Spring的自動代理方式?jīng)_突,例如我們使用BeanNameAutoProxyCreator或類似的方式顯示啟用了自動代理远豺,則它可能導致問題(例如有些增請?zhí)幚頉]有被織入)因此要么全部使用自動代理的方式奈偏,要么全部使用<aop:config../>配置方式。不要不兩者混合使用躯护。

配置切面

定義切面使用<aop:aspect../>元素惊来,使用該元素來定義切面時,其實質(zhì)是將一個已有的Spring Bean轉(zhuǎn)換成切面Bean棺滞。
因為切面Bean可以當成一個普通的SpringBean來配置裁蚁,所以可以為該切面Bean配置依賴注入矢渊。
配置<aop:aspect../>元素時可以指定如下3個屬性:
id:定義該切面的標識名;
ref:指定以指定ref所引用的的普通Bean作為切面Bean枉证。
order:指定該切面Bean的優(yōu)先等級矮男,數(shù)字越小,等級越大室谚。

配置增強處理

<aop:before.../>:Before增強處理
<aop:after../>:After增強處理
<aop:after-returning.../>:afterReturning增強處理
<aop:after-throwing../>:afterThrowing增強處理
<aop:around.../>:Around增強處理
上面的元素不能配置子元素毡鉴,但可以配置如下屬性:
pointcut:該屬性指定一個切入點表達式,Spring將在匹配該表達式的連接點時織入增強處理秒赤。
pointcut-ref:該屬性指定一個已經(jīng)存在的切入點的 名稱猪瞬,通常pointcut與pointcut-ref只需要使用其中的一個。
method:該屬性指定一個方法名入篮,指定切面Bean的該方法將作為增強處理陈瘦。
throwing:該屬性只對<aop:after-throwing../>起作用,用于指定一個形參名潮售,afterThrowing增強處理方法可以通過該形參訪問目標方法所拋出的異常甘晤。
returning:該屬性只對<aop:after-returning.../>起作用,用于指定一個形參名饲做,afterReturning增強處理方法可以通過該形參訪問目標方法的返回值线婚。

當定義切入點表達式時,XML文件配置方式和@AspectJ Annotation方式支持完全相同的切入點指示符盆均,一樣支持execution塞弊、withinargs泪姨、this游沿、targetbean等切入點指示符。

XML配置文件方式和@AspectJ Annotation方式一樣支持組合切入點表達式肮砾,但XML配置方式不再使用簡單的&&诀黍、||、仗处!作為組合運算符眯勾,而是使用and(相當于&&)、or(||)和not(!)婆誓。
如:
Spring配置文件:

<aop:config>
<aop:aspect id="fourAdviceAspect"ref="fourAdviceBean"
order="2">
<aop:after pointcut="execution(* cn.hb.spring.lee.*.*(..))"
method="release"/>
<aop:before pointcut="execution(* cn.hb.spring.lee.*.*(..))"
method="authority"/>
<aop:after-returning pointcut="execution(* cn.hb.spring.lee.*.*(..))"
method="log"returning="obj"/>
<aop:around pointcut="execution(* cn.hb.spring.lee.*.*(..))"
method="proceedTX"/>
</aop:aspect>
</aop:config>
<aop:config>
<aop:aspectid="secondAspect"ref="secondAdviceBean"order="1">
<aop:before pointcut="execution(* cn.hb.spring.lee.*.*(..)) and args(aa)"
method="authority"/>
</aop:aspect>
</aop:config>
<!-- 定義一個普通組件Bean -->
<bean id="chinese"class="cn.hb.spring.lee.Chinese"/>
<bean id="fourAdviceBean"class="cn.hb.spring.lee.FourAdviceTest"/>
<bean id="secondAdviceBean"class="cn.hb.spring.lee.SecondAdvice"/>

//業(yè)務類:

public class Chinese implements Person {
   public String sayHello(String word) {
      System.out.println("sayHello方法開始執(zhí)行...");
      return word;
  }
  public void eat(String food) {
      System.out.println("我正在吃:" + food);
  }
  public void divide() {
      int a = 5 / 0;
      System.out.println("divide執(zhí)行完畢/" + a);
  }
}

//切面Bean:

public class FourAdviceTest {
  public Object proceedTX(ProceedingJoinPoint pre)throws         Throwable {
  System.out.println("Around增強處理:執(zhí)行目標方法前吃环,執(zhí)行模擬      開啟事務.......");
  Object[] objs = pre.getArgs();
  if (objs !=null && objs.length > 0
    && objs[0].getClass() == String.class) {
    objs[0] ="被修改的參數(shù)";
    }
  Object obj = pre.proceed(objs);
  System.out.println("Around增強處理:執(zhí)行目標方法之后,模擬結(jié)  束事務.....");
  return obj +",新增加的內(nèi)容";
}
public void authority(JoinPoint jp) {
    System.out.println("Before增強:模擬權限檢查");
    System.out.println("Before增強:被織入增強處理的目標方法:"
        + jp.getSignature().getName());
    System.out.println("Before增強:目標方法的參數(shù)為:" + Arrays.toString(jp.getArgs()));
    System.out.println("Before增強:被注入增強的處理的目標對象:" + jp.getTarget());
}
public void log(JoinPoint jp, Object obj) {
    System.out.println("AfterReturning增強:獲取目標方法的返回值:" + obj);
    System.out.println("AfterReturning增強:模擬日志記錄功能.....");
    System.out.println("AfterReturning增強:被織入增強處理的目標方法:"
        + jp.getSignature().getName());
    System.out.println("AfterReturning增強:目標方法的參數(shù)為:"
        + Arrays.toString(jp.getArgs()));
    System.out.println("AfterReturning增強:被注入增強的處理的目標對象:" + jp.getTarget());
}
public void release(JoinPoint jp) {
    System.out.println("After增強:模擬方法結(jié)束后洋幻,資源釋放.....");
    System.out.println("After增強:被織入增強處理的目標方法:"
        + jp.getSignature().getName());
    System.out.println("After增強:目標方法的參數(shù)為:" + Arrays.toString(jp.getArgs()));
    System.out.println("After增強:被注入增強的處理的目標對象:" + jp.getTarget());
}
}

配置切入點

類似于@AspectJ方式郁轻,允許定義切入點來重用切入點表達式,XML配置方式也可以通過定義切入點來重用切入點表達式。

配置<aop:pointcut../>元素時通常需要指定如下兩個屬性:
id:指定該切入點的標識名好唯;
expression:指定該切入點關聯(lián)的切入點表達式竭沫。
如下面代碼:

<aop:pointcut id="myPointcut" expression="execution(* lee.*.*(..))"/>

除此之外,如果程序已經(jīng)使用Annotation定義了切入點骑篙,在<aop:pointcut ../>元素中指定切入點表達式時還有另一種用法:

<aop:pointcut expression="org.huaxia.SystemArchitecture.myPointcut()">
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末输吏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子替蛉,更是在濱河造成了極大的恐慌贯溅,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件躲查,死亡現(xiàn)場離奇詭異它浅,居然都是意外死亡,警方通過查閱死者的電腦和手機镣煮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門姐霍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人典唇,你說我怎么就攤上這事镊折。” “怎么了介衔?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵恨胚,是天一觀的道長。 經(jīng)常有香客問我炎咖,道長赃泡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任乘盼,我火速辦了婚禮升熊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绸栅。我一直安慰自己级野,他們只是感情好侈离,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布旅急。 她就那樣靜靜地躺著挨措,像睡著了一般咳蔚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上程拭,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天达传,我揣著相機與錄音,去河邊找鬼议忽。 笑死,一個胖子當著我的面吹牛十减,可吹牛的內(nèi)容都是我干的栈幸。 我是一名探鬼主播愤估,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼速址!你這毒婦竟也來了玩焰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤芍锚,失蹤者是張志新(化名)和其女友劉穎昔园,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體并炮,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡默刚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逃魄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荤西。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伍俘,靈堂內(nèi)的尸體忽然破棺而出邪锌,到底是詐尸還是另有隱情,我是刑警寧澤癌瘾,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布觅丰,位于F島的核電站,受9級特大地震影響妨退,放射性物質(zhì)發(fā)生泄漏舶胀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一碧注、第九天 我趴在偏房一處隱蔽的房頂上張望嚣伐。 院中可真熱鬧,春花似錦萍丐、人聲如沸轩端。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽基茵。三九已至,卻和暖如春壳影,著一層夾襖步出監(jiān)牢的瞬間拱层,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工宴咧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留根灯,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像烙肺,于是被迫代替她去往敵國和親纳猪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

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

  • AOP實現(xiàn)可分為兩類(按AOP框架修改源代碼的時機): 靜態(tài)AOP實現(xiàn):AOP框架在編譯階段對程序進行修改,即實現(xiàn)...
    數(shù)獨題閱讀 2,317評論 0 22
  • 1. Java基礎部分 基礎部分的順序:基本語法搏明,類相關的語法鼠锈,內(nèi)部類的語法,繼承相關的語法星著,異常的語法购笆,線程的語...
    子非魚_t_閱讀 31,623評論 18 399
  • 定義AfterReturning增強處理: AfterReturning增強處理在目標方法正常完成之后織入。 類似...
    FTOLsXD閱讀 1,117評論 0 2
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理强饮,服務發(fā)現(xiàn)由桌,斷路器,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 確定了要做音頻后并且注冊了賬號后邮丰。 首先我會根據(jù)平臺進行自己的聲音鑒定行您。這樣的來確定自己的領域,我準備在情感大類里...
    葉子ya閱讀 175評論 0 0