天天看點

Spring中的AOP(四)——基于Annotation的配置方式(二)

使用after增強處理

    spring還提供了一個after增強處理,它與afterreturning優點類似,但也有差別:

afterreturning增強處理隻有在目标方法正确完成後才會被織入

after增強處理不管目标方法如何結束(正确還是異常),它都會被織入

    正是因為這個特點,是以after增強處理必須準備處理正常傳回和異常傳回兩種情況,這種增強處理通常用于釋放資源。使用@after注解标注一個方法,即可将該方法轉換為after增強處理。使用@after注解是需要指定一個value屬性,用于指定該增強處理的切入點,既可以是一個已有的切入點,也可以直接定義切入點表達式。

    在com.abc.advice包下面增加afteradvicetest,這個類定義了一個after增強處理:

<a href="http://my.oschina.net/itblog/blog/210807#">?</a>

1

2

3

4

5

6

7

<code>@aspect</code>

<code>public</code> <code>class</code> <code>afteradvicetest {</code>

<code>    </code><code>@after</code><code>(value=</code><code>"execution(* com.abc.servie.impl.*.afteradvice*(..))"</code><code>)</code>

<code>    </code><code>public</code> <code>void</code> <code>releaseresource() {</code>

<code>        </code><code>system.out.println(</code><code>"模拟釋放資料庫連接配接"</code><code>);</code>

<code>    </code><code>}</code>

<code>}</code>

     并在advicemanager類中增加以下内容:

<code>//将被afteradvice的releaseresource方法比對</code>

<code>public</code> <code>void</code> <code>afteradvice() {</code>

<code>    </code><code>system.out.println(</code><code>"方法: afteradvice"</code><code>);</code>

    上面定義了一個after增強處理,不管切入點的目标方法如何結束,該增強處理都會被織入。下面是測試結果:

Spring中的AOP(四)——基于Annotation的配置方式(二)

使用around增強處理

    @around注解用于标注around增強處理,它近似等于before增強處理和afterreturning增強處理的總和,around增強處理既可以在執行目标方法前織入增強動作,也可以在目标方法之後織入增強動作。

    與@before和@afterreturning不同的是,@around甚至可以決定目标方法在什麼時候執行,如何執行,甚至可以完全阻止目标方法的執行。@around可以修改目标方法的參數值,也可以修改目标方法的傳回值。

    @around的功能雖然強大,但通常需要線上程安全的環境下使用,是以,如果使用普通的@before和@afterreturning就能解決的問題,就沒有必要使用@around了。如果需要目标方法執行之前和執行之後共享某種資料狀态,則應該考慮使用@around;尤其是需要使用增強處理阻止目标方法的執行,或者需要改變目标方法的參數和執行後的傳回值時,就隻能使用@around了。

    可以想象,使用@around時,也需要指定一個value屬性,這個屬性依然是用于指定切入點。另外,當定義一個around增強處理時,該方法的第一個形參必須是proceedingjoinpoint類型(就是說至少包含一個形參),在增強處理方法體内,調用proceedingjoinpoint的proceed()方法才會執行目标方法——這就是around增強處理可以完全控制目标方法的執行時機、如何執行的關鍵,如果增強處理的方法體内沒有調用這個proceed()方法,則目标方法不會執行。

    調用proceed()方法時,還可以傳入一個object[]對象,該數組中的值将被傳入目标方法作為執行方法的實參。是以我們可以通過這個參數,修改方法的參數值。

    在com.abc.advice包下面增加aroundadvicetest,這個類定義了一個around增強處理:

8

9

10

11

12

13

14

15

16

17

18

19

20

<code>package</code> <code>com.abc.advice;</code>

<code>import</code> <code>org.aspectj.lang.proceedingjoinpoint;</code>

<code>import</code> <code>org.aspectj.lang.annotation.around;</code>

<code>import</code> <code>org.aspectj.lang.annotation.aspect;</code>

<code>public</code> <code>class</code> <code>aroundadvicetest {</code>

<code>    </code><code>@around</code><code>(value=</code><code>"execution(* com.abc.service.*.around*(..))"</code><code>)</code>

<code>    </code><code>public</code> <code>object process(proceedingjoinpoint point) </code><code>throws</code> <code>throwable {</code>

<code>        </code><code>system.out.println(</code><code>"模拟執行目标方法前的增強處理:事務開始..."</code><code>);</code>

<code>        </code><code>//修改目标方法的參數</code>

<code>        </code><code>string[] params = </code><code>new</code> <code>string[]{</code><code>"param1"</code><code>};</code>

<code>        </code><code>//執行目标方法,并儲存目标方法執行後的傳回值</code>

<code>        </code><code>object returnvalue = point.proceed(params);</code>

<code>        </code><code>system.out.println(</code><code>"模拟執行目标方法後的增強處理:事務結束..."</code><code>);</code>

<code>        </code><code>//傳回修改後的傳回值</code>

<code>        </code><code>return</code> <code>"方法實際傳回值:"</code> <code>+ returnvalue + </code><code>",這是傳回值的字尾"</code><code>;</code>

    上面定義了一個aroundadvicetest切面,該切面包含了一個around增強處理:process()方法,該方法中第一行代碼用于模拟調用目标方法之前的處理,第二行修改了目标方法的第一個參數,接下來調用目标方法,後面模拟調用目标方法之後的處理和對傳回值的修改。正如前面說的,通過這個process方法,我們可以增加類似于@before和@afterreturning的增強處理,可以決定什麼時候執行目标方法,可以修改目标方法的參數值,還可以修改目标方法的傳回值,真是想做什麼就做什麼啊!

    在advicemanager類中增加以下内容:

<code>//将被aroundadvice的process方法比對</code>

<code>public</code> <code>string aroundadvice(string param1) {</code>

<code>    </code><code>system.out.println(</code><code>"方法: aroundadvice"</code><code>);</code>

<code>    </code><code>return</code> <code>param1;</code>

    在com.abc.main.aoptest中加入方法的調用,觸發切點:

<code>string result = manager.aroundadvice(</code><code>"param1"</code><code>);</code>

<code>system.out.println(</code><code>"傳回值:"</code> <code>+ result);</code>

    執行測試類,結果如下:

Spring中的AOP(四)——基于Annotation的配置方式(二)

    需要注意的是,當調用proceedingjoinpoint的proceed()方法時,傳入的object[]參數值将作為目标方法的參數,如果這個數組長度與目标方法的參數個數不等,或者數組元素的類型和目标方法的參數類型不比對,程式就會出現異常。