spring AOP應用

轉自:http://wb284551926.iteye.com/blog/1887650html

最近新項目要啓動,在搭建項目基礎架構的時候,想要加入日誌功能和執行性能監控的功能,想了不少的想法,最後仍是想到用spring的aop功能,一是不須要寫那麼多的重複代碼,二是靈活好用,好了如今就講講這個aop功能的使用。(須要的jar包:spring.jar、asm-2.2.3.jar、asm-commons-2.2.3.jar、aopalliance.jar、aspectjweaver.jar、cglib-nodep-2.1_3.jar,能夠忽略版本號)java

1.創建一個切入類,包括doBefore、doAround、doAfter、doThrowing等方法。node

Java代碼   收藏代碼
  1. /***************************************** 
  2.  * @類名:com.util.TestAspect 
  3.  * @做者:王博 
  4.  * @時間:Jun 15, 2013 
  5.  * @版本:1.0 
  6.  * @描述: 
  7.  * @修改人員: 
  8.  * @修改時間: 
  9.  * @修改說明: 
  10.  *****************************************/  
  11. package com.util;  
  12.   
  13. import org.aspectj.lang.JoinPoint;  
  14. import org.aspectj.lang.ProceedingJoinPoint;  
  15.   
  16. public class TestAspect {  
  17.       public void doAfter(JoinPoint jp) {    
  18.             System.out.println("log Ending method: "    
  19.                     + jp.getTarget().getClass().getName() + "."    
  20.                     + jp.getSignature().getName());    
  21.         }    
  22.         
  23.         public Object doAround(ProceedingJoinPoint pjp) throws Throwable {    
  24.             long time = System.currentTimeMillis();    
  25.             Object retVal = pjp.proceed();    
  26.             time = System.currentTimeMillis() - time;    
  27.             System.out.println("process time: " + time + " ms");    
  28.             return retVal;    
  29.         }    
  30.         
  31.         public void doBefore(JoinPoint jp) {    
  32.             System.out.println("log Begining method: "    
  33.                     + jp.getTarget().getClass().getName() + "."    
  34.                     + jp.getSignature().getName());    
  35.         }    
  36.         
  37.         public void doThrowing(JoinPoint jp, Throwable ex) {    
  38.             System.out.println("method " + jp.getTarget().getClass().getName()    
  39.                     + "." + jp.getSignature().getName() + " throw exception");    
  40.             System.out.println(ex.getMessage());    
  41.         }   
  42. }  

 2.在spring的配置文件中加入aop配置,proxy-target-class="true"紅色部分*注意*,不加入這個,action是攔截不到的,切記spring

com.neau.project.*.*.*.*(..))"  這裏主要注意的是express

例如你的包結構是com.xxx.action.actionclass  你須要這樣寫才能攔截到 com.xxx.action.actionclass.*  架構

最後的.*是表明actionclass中的方法。下面有這個配置的具體說明模塊化

若是要放行一些方法,好比get/set方法能夠用 and 關鍵字,例如性能

execution(* com.neau.project.*.*.*.*(..)) and !execution(* com.neau.project.*.*.*.get*(..)) and !execution(* com.neau.project.*.*.*.set*(..))this

Xml代碼   收藏代碼
  1. <aop:config <span style="color: #ff0000;">proxy-target-class="true"</span>   
  2.        <aop:aspect id="TestAspect" ref="aspectBean">    
  3.            <!--配置com.neau.project.*.*.*.*包下全部類或接口的全部方法-->    
  4.            <aop:pointcut id="AOPService"    
  5.                expression="execution(* <span style="color: #ff0000;">com.neau.project.*.*.*.*</span>(..))" />              <aop:before pointcut-ref="AOPService" method="doBefore"/>    
  6.            <aop:after pointcut-ref="AOPService" method="doAfter"/>    
  7.            <aop:around pointcut-ref="AOPService" method="doAround"/>    
  8.            <aop:after-throwing pointcut-ref="AOPService" method="doThrowing" throwing="ex"/>    
  9.        </aop:aspect>    
  10.    </aop:config>    
  11.  <bean id="aspectBean" class="com.util.TestAspect" />    

 

3.啓動項目,執行spa

訪問action

Java代碼   收藏代碼
  1. log Begining method: com.neau.project.logon.action.LogonAction.test  
  2. 2013-06-16 15:31:56,737 - {pstm-100001} Executing Statement:    select count(*) from rdtteam t    
  3. 2013-06-16 15:31:56,737 - {pstm-100001} Parameters: []  
  4. 2013-06-16 15:31:56,737 - {pstm-100001} Types: []  
  5. 2013-06-16 15:31:56,749 - {pstm-100004} Executing Statement:    select t.* from rdtteam t limit ?,?     
  6. 2013-06-16 15:31:56,749 - {pstm-100004} Parameters: [0, 20]  
  7. 2013-06-16 15:31:56,749 - {pstm-100004} Types: [java.lang.Integer, java.lang.Integer]  
  8. log Ending method: com.neau.project.logon.action.LogonAction.test  
  9. process time: 261 ms  
  10. log Begining method: com.neau.project.logon.action.LogonAction.getRdtTeamPage  
  11. log Ending method: com.neau.project.logon.action.LogonAction.getRdtTeamPage  
  12. process time: 0 ms  
  13. log Begining method: com.neau.project.logon.action.LogonAction.get_rdtTeamList  
  14. log Ending method: com.neau.project.logon.action.LogonAction.get_rdtTeamList  
  15. process time: 0 ms  

 aop就這樣實現了攔截action,簡單吧,簡單的工做實現大功能是我等苦逼開發者的目標。

 

偷點別的寫好的吧。

 

《Spring參考手冊》中定義瞭如下幾個AOP的重要概念,結合以上代碼分析以下:

  • 切面(Aspect) :官方的抽象定義爲「一個關注點的模塊化,這個關注點可能會橫切多個對象」,在本例中,「切面」就是類TestAspect所關注的具體行爲,例如,AServiceImpl.barA()的調用就是切面TestAspect所關注的行爲之一。「切面」在ApplicationContext中<aop:aspect>來配置。
  • 鏈接點(Joinpoint) :程序執行過程當中的某一行爲,例如,AServiceImpl.barA()的調用或者BServiceImpl.barB(String _msg, int _type)拋出異常等行爲。
  • 通知(Advice) :「切面」對於某個「鏈接點」所產生的動做,例如,TestAspect中對com.spring.service包下全部類的方法進行日誌記錄的動做就是一個Advice。其中,一個「切面」能夠包含多個「Advice」,例如TestAspect
  • 切入點(Pointcut) :匹配鏈接點的斷言,在AOP中通知和一個切入點表達式關聯。例如,TestAspect中的全部通知所關注的鏈接點,都由切入點表達式execution(* com.spring.service.*.*(..))來決定
  • 目標對象(Target Object) :被一個或者多個切面所通知的對象。例如,AServcieImpl和BServiceImpl,固然在實際運行時,Spring AOP採用代理實現,實際AOP操做的是TargetObject的代理對象。
  • AOP代理(AOP Proxy) 在Spring AOP中有兩種代理方式,JDK動態代理和CGLIB代理。默認狀況下,TargetObject實現了接口時,則採用JDK動態代理,例如,AServiceImpl;反之,採用CGLIB代理,例如,BServiceImpl。強制使用CGLIB代理須要將 <aop:config> 的 proxy-target-class 屬性設爲true

       通知(Advice)類型

  • 前置通知(Before advice) :在某鏈接點(JoinPoint)以前執行的通知,但這個通知不能阻止鏈接點前的執行。ApplicationContext中在<aop:aspect>裏面使用<aop:before>元素進行聲明。例如,TestAspect中的doBefore方法
  • 後通知(After advice) :當某鏈接點退出的時候執行的通知(不管是正常返回仍是異常退出)。ApplicationContext中在<aop:aspect>裏面使用<aop:after>元素進行聲明。例如,TestAspect中的doAfter方法,因此AOPTest中調用BServiceImpl.barB拋出異常時,doAfter方法仍然執行
  • 返回後通知(After return advice) :在某鏈接點正常完成後執行的通知,不包括拋出異常的狀況。ApplicationContext中在<aop:aspect>裏面使用<after-returning>元素進行聲明。
  • 環繞通知(Around advice) :包圍一個鏈接點的通知,相似Web中Servlet規範中的Filter的doFilter方法。能夠在方法的調用先後完成自定義的行爲,也能夠選擇不執行。ApplicationContext中在<aop:aspect>裏面使用<aop:around>元素進行聲明。例如,TestAspect中的doAround方法。
  • 拋出異常後通知(After throwing advice) : 在方法拋出異常退出時執行的通知。 ApplicationContext中在<aop:aspect>裏面使用<aop:after-throwing>元素進行聲明。例如,TestAspect中的doThrowing方法。

       切入點表達式

  • 一般狀況下,表達式中使用」execution「就能夠知足大部分的要求。表達式格式以下:
Java代碼    收藏代碼
  1. execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)  

modifiers-pattern:方法的操做權限

ret-type-pattern:返回值

declaring-type-pattern:方法所在的包

name-pattern:方法名

parm-pattern:參數名

throws-pattern:異常

其中,除ret-type-pattern和name-pattern以外,其餘都是可選的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值爲任意類型;方法名任意;參數不做限制的全部方法。

  • 通知參數

能夠經過args來綁定參數,這樣就能夠在通知(Advice)中訪問具體參數了。例如,<aop:aspect>配置以下

Java代碼    收藏代碼
  1. <aop:config>  
  2.     <aop:aspect id="TestAspect" ref="aspectBean">  
  3.         <aop:pointcut id="businessService"  
  4.             expression="execution(* com.spring.service.*.*(String,..)) and args(msg,..)" />  
  5.             <aop:after pointcut-ref="businessService" method="doAfter"/>  
  6.     </aop:aspect>  
  7. </aop:config>  

TestAspect的doAfter方法中就能夠訪問msg參數,但這樣以來AService中的barA()和BServiceImpl中的barB()就再也不是鏈接點,由於execution(* com.spring.service.*.*(String,..))只配置第一個參數爲String類型的方法。其中,doAfter方法定義以下:

Java代碼    收藏代碼
  1. public void doAfter(JoinPoint jp,String msg)  
  •   訪問當前的鏈接點

任何通知(Advice)方法能夠將第一個參數定義爲 org.aspectj.lang.JoinPoint 類型。JoinPoint 接口提供了一系列有用的方法, 好比 getArgs() (返回方法參數)、getThis() (返回代理對象)、getTarget() (返回目標)、getSignature() (返回正在被通知的方法相關信息)和 toString()(打印出正在被通知的方法的有用信息。

 

warning no match for this type name: com.zrm.service [Xlint:invalidAbsoluteTypeName]

<aop:config>
   <!-- 切入點 -->
   <aop:pointcut id="gkServicePct" expression="execution(* com.zrm.service.*(..))" />
   <aop:advisor pointcut-ref="gkServicePct" advice-ref="gkTxAdvice" order="0" />
</aop:config>

出現warning no match for this type name: com.zrm.service [Xlint:invalidAbsoluteTypeName]錯誤

配置事務時,必定注意expression="execution(* com.zrm.service.*(..))" 應該爲

expression="execution(* com.zrm.service.*.*(..))" ,這樣,切點才定位到方法上了。

 

感謝:http://pandonix.iteye.com/blog/336873

感謝:http://hi.baidu.com/gglzf4/item/a58624e2f962d113585dd832

感謝:http://bbs.csdn.net/topics/350180595    11樓的同志

感謝:http://blog.sina.com.cn/s/blog_5f53615f0101ijdl.html

 

看了那麼童鞋的經驗讓我少走了很多彎路,看來我就是吃百家飯長大孩紙的命,傷不起啊。苦逼的開發者傷不起啊。

相關文章
相關標籤/搜索