除了前面介紹的基於JDK1.5的註解方式來定義切面,切入點和加強處理外,Spring AOP也容許直接使用XML配置文件來管理它們。在JDK1.5以前,只能使用配置文件的方式來管理,在Spring2.X後提供了一個新的aop命名空間來定義切面、切入點和加強處理。java
相比之下,使用XML配置文件方式有以下優勢:
數據庫
若是沒有使用JDK1.5以上版本,只能使用XML配置文件的方式express
對早期的Spring用於來講更加習慣,並且這種方式容許使用純粹的POJO來支持AOPthis
採用XML配置方式時,咱們能夠清晰的看到系統中存在哪些切面spa
同時,XML配置文件的方式也有以下缺點:代理
不能將切面,切入點和加強處理等封裝到一個地方。當咱們須要查看切面、切點和加強處理時,必須同時結合Java文件和XML配置文件code
XML配置文件方式比@AspectJ方式有更多限制:僅支持「singleton」切面Bean,不能在XML中組合多個命名鏈接點的聲明xml
除此以外,@AspectJ切面還有一個優勢就是能被Spring AOP和AspectJ同時支持,若是有一天咱們須要將應用改成AspectJ來實現AOP,使用@AspectJ將很是容易遷移。
對象
在Spring的配置文件中,全部的切面、切點和加強處理都必須定義在<aop:config../>元素內部。<beans../>元素能夠包含多個<aop:config../>元素,一個<aop:config../>能夠包含pointcut、advisor和aspect元素,且這三個元素須要按照此順序來定義。
事務
注意:當咱們使用<aop:config../>方式進行配置時,可能與Spring的自動代理方式相互衝突,所以,建議要麼所有使用<aop:config../>配置方式,要麼所有使用自動代理方式,不要把二者混合使用。
配置切面
配置<aop:config../>元素時,實質是將已有的Spring Bean轉換成切面Bean,因此須要先定義一個普通的Spring Bean。由於切面Bean能夠當成一個普通的Spring Bean來配置,因此咱們徹底能夠爲該切面Bean配置依賴注入。當切面Bean的定義完成後,經過<aop:congig../>元素中是喲個ref屬性來引用該Bean,就能夠將該Bean轉換成切面Bean了。配置<aop:config../>元素時能夠指定以下三個屬性:
id:該切面Bean的標識名
ref:指定將要被轉換成切面Bean的的普通Bean的id
order:指定該切面Bean的優先級,值越小,優先級越高
以下配置片斷定義了一個切面:
<!-- 定義普通的Bean實例 --> <bean id="afterAdviceBean" class="com.abc.advice.AfterAdviceBean" /> <aop:config> <!-- 將容器中的afterAdviceBean轉換成切面Bean --> <aop:aspect id="afterAdviceAspect" ref="afterAdviceBean"> ... </aop:aspect> </aop:config>
上面的配置中,將一個AfterAdviceBean類型普通的Bean對象afterAdviceBean轉換成了切面Bean對象afterAdviceAspect。
配置加強處理
與使用@AspectJ徹底同樣,使用XML同樣能夠配置Before、After、AfterReturning、AfterThrowing和Around 5種加強處理,並且徹底支持和@Aspect徹底同樣的語義。使用XML配置加強處理分別依賴於以下幾個元素:
<aop:before../>:配置Before加強處理
<aop:after../>:配置After加強處理
<aop:after-returning../>:配置AfterReturning加強處理
<aop:after-throwing../>:配置AfterThrowing加強處理
<aop:around../>:配置Around加強處理
這些元素都不支持使用子元素,但一般能夠指定以下屬性:
pointcut:指定一個切入點表達式,Spring將在匹配該表達式的鏈接點織入加強處理
pointcut-ref:指定一個已經存在的切入點名稱,一般pointcut和pointcut-ref只需使用其中之一
method:指定一個方法名,指定切面Bean的該方法做爲加強處理
throwing:只對<aop:after-throwing../>元素有效,用於指定一個形參名,AfterThrowing加強處理方法,可經過該形參訪問目標方法所拋出的異常
returning:只對<aop:after-returning../>元素有效,用於指定一個形參名,AfterThrowing加強處理方法,可經過該形參訪問目標方法的返回值
既然選擇XML配置文件的方式來管理切面、切點和加強處理,那麼切面類裏定義切面,切點和加強處理的註解就能夠所有刪除了。
定義切點時,XML配置方式和@AspectJ註解方式支持徹底相同的切點指示符,同樣能夠支持execution、within、args、this、target和bean等切點提示符。另外,XML配置文件方式也和@AspectJ方式同樣支持組合切入點表達式,但XML配置方式再也不使用簡單的&&、|| 和 ! 做爲組合運算符(由於直接在XML文件中須要使用實體引用來表示他們),而是使用以下三個組合運算符:and(至關於&&)、or(至關於||)和not(至關於!)。 下面是一個使用<aop:congig../>的例子,這是把前面的例子中關於切面切點和加強處理的註解去掉後,使用XML配置文件來從新實現這些切面切點的功能:
<bean id="adviceTest" class="com.abc.advice.AdviceTest" /> <aop:config> <!-- 注意這裏可使用order屬性爲Aspect指定優先級 --> <aop:aspect id="firstAspect" ref="adviceTest" order="2"> <!-- @Before切點 --> <aop:before pointcut="execution(* com.abc.service.*.*(..))" method="permissionCheck"/> <!-- @After切點 --> <aop:after pointcut="execution(* com.abc.service.*.*(..))" method="releaseResource"/> <!-- @AfterReturning切點 --> <aop:after-returning pointcut="execution(* com.abc.service.*.*(..))" method="log"/> <!-- @AfterThrowing切點 --> <aop:after-throwing pointcut="execution(* com.abc.service.*.*(..))" method="handleException"/> <!-- @Around切點(多個切點提示符使用and、or或者not鏈接) --> <aop:around pointcut="execution(* com.abc.service.*.*(..)) and args(name,time,..)" method="process"/> </aop:aspect> </aop:config>
上面的定義中,特地爲firstAspec指定了order=2,代表firstAspect的優先級爲2,若是這個XML文件中還有order=1的Aspect,那麼這個Aspect將被Spring AOP優先織入。其執行結果,和前面幾篇文章中介紹的相同,這裏再也不給出。
配置切點
在Spring中經過<aop:pointcut../>元素來定義切點。當把<aop:pointcut../>元素做爲<aop:config../>的子元素時,代表該切點能夠被多個切面共享;當把<aop:pointcut../>元素做爲<aop:aspect../>的子元素時,代表該切點只能在這個切面內使用。配置<aop:pointcut../>時,一般須要配置以下兩個屬性:
id:指定該切點的標識名
expression:指定該切點關聯的切點表達式
以下的配置定義了一個簡單的切點:
<aop:pointcut id="point1" expression="execution(* com.abc.service.*.*(..))" />
另外,若是程序中已經使用註解的方式定義了切點,在<aop:pointcut../>元素中指定切入點表達式時還有另外一種用法,看例子:
<aop:pointcut id="point2" expression="com.abc.service.AdviceTest.myPointcut()" />
下面的程序中定義了一個AfterThrowing加強處理,包含該加強處理的切面類以下:
package com.abc.advice; public class AfterThrowingAdviceTest { //定義一個普通方法做爲加強處理方法,這個方法名將在XML配置文件中指定 public void doRecoveryAction(Throwable th) { System.out.println("目標方法拋出異常:" + th); System.out.println("模擬數據庫事務恢復"); } }
與前面的切面類徹底相似,該Java類就是一個普通的Java類。下面的配置文件將負責配置該Bean實例,並將該Bean轉換成切面Bean:
<bean id="afterThrowingAdviceTest" class="com.abc.advice.AfterThrowingAdviceTest" /> <aop:config> <!-- 這個切點將能夠被多個<aop:aspect../>使用 --> <aop:pointcut id="myPointcut" expression="execution(* com.abc.service.*.*(..))" /> <!-- 這個aspect由上面的Bean afterThrowingAdviceTest轉化而來 --> <aop:aspect id="aspect1" ref="afterThrowingAdviceTest"> <!-- 定義一個AfterThrowing加強處理,指定切入點以切面Bean中 的doRecoverryAction做爲加強處理方法 --> <aop:after-throwing pointcut-ref="myPointcut" method="doRecoveryAction" throwing="th" /> </aop:aspect> </aop:config>
上面的<aop:pointcut../>元素定義了一個全局的切點myPointcut,這樣其餘切面Bean就能夠屢次複用這個切點了。<aop:after-throwing../>元素中,使用pointcut-ref屬性指定了一個已經存在的切點。
【完】