2013年1月20日 星期日

spring 3 aop 簡單實現 - 透過Annotation.

前言 : 若你是搭配 struts2的話,請取消繼承 ActionSupport。否則將會遇到java.lang.NoSuchMethodException: $Proxy..這一類的問題。


AOP 是幹麼的 ? 我一直覺得這個名詞翻譯的很不吸引人,導致很多人一聽到就退縮了。那至少你是聽過「注入」吧,就是 Spring標榜的核心功能。AOP 只要翻成「插入」就行了。雖然聽來有一點色情,不過先這樣翻譯比較吸引人。

物理上的插入還要定義方向,在AOP的術語來說,他是Cross-cutting,也就是橫的插進去。想像程式碼是一個磚頭,現在我在上面放一片木頭( 做log ),在下面也放一片木頭 (log ),我這個木頭是共用的,所以不用因為每一個磚頭就製造一片新的木頭。

我們再想一個案例 : 客戶反應執行某段程式的時候異常的慢,他們和你攤牌了 : 超過7秒的真的無法接受,請全面檢查。

主案眉頭一皺,請你把所有使用者「按下去」到得到結果的所有功能,中間執行時間做一個EXCEL出來,星期一開會檢討。

若沒有AOP 的話,好吧,你不會想拿手錶出來計時吧? 

如果有一個東西可以像盒子一樣,把你所有的程式像樂高積木裝進去,當進去要執行的時候紀錄一次時間,出來的時候紀錄一次時間,只要超過7秒就記在什麼LOG檔吧,那該有多好?

AOP 可以解決類似這樣的問題。畢竟你不想把所有的程式都在開始與結束寫一次,當然你可以透過攔截器或是什麼過濾器達到,不過AOP 的動配裝配蠻有趣的,不彷也可以了解一下。

首先我們要先寫一個紀錄時間的類別,這玩意叫Aspect,切入面,他是實際會插到程式裡的東西,所以你裡面自然會想到 : 前插、後插、前後插(環繞)、異常插等等,為了不要搞的太複雜就只說前插入與後插入。

先寫一個class

  1. package aop;
  2. import org.apache.log4j.Logger;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.annotation.After;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Before;
  7. import org.aspectj.lang.annotation.Pointcut;
  8. @Aspect
  9. public class LogExecuteTime {
  10.    
  11.    
  12.     @Pointcut("execution(* action.IndexAction.*(..))")
  13.     private void anyMethod(){}
  14.    
  15.     @Before("anyMethod()")
  16.     public void beforeAdvice(JoinPoint jp){
  17.         String noti = jp.getTarget().getClass().getName()+" "+jp.getSignature().getName();
  18.         System.out.println("before" + noti+" has been started.");
  19.    
  20.     }
  21.    
  22.     @After("anyMethod()")
  23.     public void afterAdvice(JoinPoint jp){
  24.         String noti = jp.getTarget().getClass().getName()+" "+jp.getSignature().getName();
  25.        
  26.         System.out.println("after" + noti+" has been executed.");
  27.     }
  28. }

這邊伴隨著annotation做直觀的設定。比較特別的是你要先定義哪些程式需要插入。

  1. @Pointcut("execution(* action.IndexAction.*(..))")
  2.     private void anyMethod(){}

這裡代表IndexAction這個類別下的所有方法都要被套用。
接下來你想要前插,就寫@before的方法,後插就寫@after的方法。
我們在軟體工程常常講去耦合,aop 就是一個超好的例子。怎麼說?
因為要被插入的類別中,完全不知道這件事的存在! 
也就是悄悄的來,悄悄的去,有一點像百貨公司的人數計算器一樣,進場的民眾不需要做什麼,但是臨時在入口裝一個計數器,就知道進場有多少人了。如果客戶、主管滿意後,這個aop甚至可以告一段落,主程式完全不受影響。

ok,但是在xml 中還是要把這個程式交由Spring管理,所以請先加

<aop:aspectj-autoproxy/> ( 這代表要使用aspectj)

再把計時器加入管理即可。
<bean id="logAspect" class="aop.LogExecuteTime" />


所有的耦合只存在於計時器的類別
  @Pointcut("execution(* action.IndexAction.*(..))")

所以當你要增加、減少控制項目時,非常的簡單。
我建議採用annotation甚於xml,看程式的時候即可一目了然,不需要再看xml來對照。

沒有留言:

張貼留言