Spring中AOP實現


1.什么是SpringAOP

什么是aop:Aspect Oriented Programming的縮寫,面向切面編程,通過預編譯和動態代理實現程序功能的
統一維護的一種技術
主要功能:日志記錄,性能統計,安全控制,事務處理,異常處理等

2.SpringAOP框架的用途

提供了聲明的企業服務,特別是EJB的替代服務的聲明
允許用戶控制自己的方面,以完成OOP和AOP的互補使用

OOP:模擬真實的世界,一切皆是對象

3.AOP的實現方式

下邊這兩種Spring都是支持的

3.1預編譯
-AspectJ  完整的面向切面編程解決方案--》spring不是完整的解決方案,不過spring提供比較好的實現方式,當然spring是同時也是支持這種方式的,這也是一種常用的方式

3.2運行期間動態代理(JDK動態代理,CGLib動態代理)
-SpringAop,JbossAop

Spring的AOP使用純java實現,無需特殊的編譯過程,不需要控制類的加載器層次,目前只支持方法的執行的連接點(通知Spring Bean某個方法執行)
不是為了提供完整AOP實現;而是側重於一種AOP於IOC容器之間的整合,SpringAOP不會AspectJ(完整的AOP解決方案)競爭

Spring沒有使用AspectJ的時候,也可以通過如下方式實現AOP

Spring AOP 默認使用標准的JavaSE動態代理作為AOP代理,這使得任何接口(或者集合)都可以被代理
Spring AOP 中也可以使用CGLIB代理(如果一個業務對象沒有實現一個接口)
有接口的:使用JDK的動態里
無接口的:使用CGLIB代理

4.SpringAOP中的一些概念

在實際使用SpringAOP之前,了解他的概念是必不可少的一個過程,
 

SpringAOP主要圍繞以下概念展開:

切面(Aspect)一個關注點的模塊化,這個關注點可能會橫切多個對象
連接點(Joinpoint)程序執行過程中某個特定的連接點
通知(Advice) 在切面的某個特的連接點上執行的動作
切入點(Pointcut)匹配連接的斷言,在Aop中通知和一個切入點表達式關聯
引入(Intruduction) 在不修改類代碼的前提下,為類添加新的方法和屬性
目標對象(Target Object) 被一個或者多個切面所通知的對象
Aop代理(AOP Proxy) AOP框架創建的對象,用來實現切面契約(aspect contract)(包括方法執行等)
織入(Weaving)把切面連接到其他的應用程序類型或者對象上,並創建一個被通知的對象,氛圍:編譯時織入,類加載時織入,執行時織入

通知類型Advice:

前置通知(before advice) 在某個連接點(jion point)之前執行的通知,但不能阻止連接點前的執行(除非拋出一個異常)
返回后通知(after returning advice)在某個連接點(jion point)正常執行完后執行通知
拋出異常通知(after throwing advice) 在方法異常退出時執行的通知
后通知(after(finally) advice)在方法拋出異常退出時候的執行通知(不管正常返回還是異常退出)
環繞通知(around advice) 包圍一個連接點(jion point)的通知
 

切入點Pointcut:SpringAOP占時僅僅支持方法的連接點

例如定義切入點表達式 execution(* com.sample.service.impl..*.*(..))
execution()是最常用的切點函數,其語法如下所示:
 整個表達式可以分為五個部分:
 1、execution(): 表達式主體。
 2、第一個*號:表示返回類型,*號表示所有的類型。
 3、包名:表示需要攔截的包名,后面的兩個句點表示當前包和當前包的所有子包,com.sample.service.impl包、子孫包下所有類的方法。
 4、第二個*號:表示類名,*號表示所有的類。
 5、*(..):最后這個星號表示方法名,*號表示所有的方法,后面括弧里面表示方法的參數,兩個句點表示任何參數。
 
execution(public * *(..)) 切入點為執行所有的public方式時
execution(* set*(..)) 切入點執行所有的set開始的方法時
execution(* com.xyz.service.Account.*(..)) 切入點執行Account類的所有方法時
execution(* com.xyz.service.*.*(..))切入點執行com.xyz.service包下的所有方法時
execution(* com.xyz.service..*.*(..)) 切入點執行com.xyz.service包以及其子包的所有的方法時

 


上邊這種方式aspectj和springaop通用的,其他方式可以自己查找資料

 

推薦:

http://blog.csdn.net/abcd898989/article/details/50809321

http://blog.csdn.net/peng658890/article/details/7223046

 

5.SpringAOP實現

上邊的一些概念,看過后可能還是不懂,可以自行查閱資料,下邊我也會說明

我們在Java項目開發中,AOP常見的配置有如下3種:

a.基於SpringAOP容器的實現,使用AspectJ(Spring封裝了AspectJ的使用),這是一種比較常用的方式,可以很容易看清代碼結構

b.運行期間的動態代理實現,這是一種比較老的實現方式,比較繁瑣

c.注解實現,這種方式開發起來簡單,但是不利於后期維護,比如說很難找出你所有使用了SpringAOP注解的地方

這里我主要介紹第一種,和第二種的使用

5.1SpringAOP中的容器實現

5.1.1 前置通知 before

某個需要切入的方法之前執行切面中的方法
 
 
Spring所有的切面通知都必須放在一個<aop:config>內(可以配置多個<aop:config>元素),每一個<aop:config>可以包含pointcut,adviso
和aspect元素(注意這些元素的出現是由順序的)
 
配置文件: spring-aop-schema-advice.xml

聲明了切面類,當切入點中匹配到了類名包含BIZ字符串的類時,選取面類中的一個方法,在選取某種Adivice通知,切入該方法的執行過程
其中:aop:aspect 中id的值任意(表意性強)  ref的值為切面類的id值
    aop:pointcut 中expression寫切入點表達式,說明那個方法可能需要做切入點
    aop:before 中method的值為切面中的方法名說明切入那個方法,pointcut-ref的值為切入點的id值
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.  xmlns:aop="http://www.springframework.org/schema/aop"  
  5.  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  6.  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">  
  7.       
  8.     <!-- 切面類 -->  
  9.     <bean id="myAspect" class="com.xxx.spring.aop.bean.annotation.aop.MyAspect"></bean>  
  10.       
  11.     <!-- 業務類 -->  
  12.     <bean id="aspectBiz" class="com.xxx.spring.aop.bean.annotation.aop.AspectBiz"></bean>  
  13.     <!-- aop配置 可以配置多個-->  
  14.     <aop:config>  
  15.     <!-- 切面類 -->  
  16.         <aop:aspect id="aspectTest" ref="myAspect">  
  17.         <!-- 切入點  標識切入點 aop包下類名包含Biz的類的所有方法-->  
  18.             <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>  
  19.             <!-- 通知 ,通過切入點切入切入切面類中的before方法-->  
  20.             <aop:before method="before" pointcut-ref="myPointcut"/>  
  21.         </aop:aspect>  
  22.     </aop:config>  
  23. </beans>  

切面類:
 
切面類中的某個方法,一般是用於切入業務類中的某個方法在某種狀態時切入
[java] view plain copy
  1. /* 
  2.  * 聲明一個切面類 
  3.  * */  
  4. public class MyAspect {  
  5.       
  6.     public void before(){  
  7.         System.out.println("aspect before");  
  8.     }  
  9.   
  10. }  
 
業務類:
[java] view plain copy
  1. //業務類  
  2. public class AspectBiz {  
  3.       
  4.     public void biz(){  
  5.         System.out.println("Aspect biz");  
  6.     }  
  7.   
  8. }  
 
測試:
[java] view plain copy
  1. @Test  
  2. public void aspectBefore(){  
  3.     ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/spring-aop-schema-advice.xml");  
  4.     AspectBiz aspectBiz = (AspectBiz) ac.getBean("aspectBiz");  
  5.     aspectBiz.biz();  
  6. }  
結果:
[plain] view plain copy
  1. aspect before  
  2. Aspect biz  
通過結果可以看出,前置通知在業務類AspectBiz的方法biz執行之前執行了before方法
 

5.1.2后置通知after-returning

某個需要切入的方法執行完成之后執行切面中指定的方法
 
配置文件: spring-aop-schema-advice.xml
[html] view plain copy
  1. <aop:config>  
  2.     <!-- 切面類 -->  
  3.         <aop:aspect id="aspectTest" ref="myAspect">  
  4.         <!-- 切入點  標識切入點 aop包下類名以Biz結尾的類的所有方法-->  
  5.             <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>  
  6.             <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->  
  7.             <aop:before method="before" pointcut-ref="myPointcut"/>  
  8.             <!-- 返回之后的通知 -->  
  9.             <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>  
  10.         </aop:aspect>  
  11. </aop:config>  
切面類:
添加afterReturning方法
[java] view plain copy
  1. /* 
  2.  * 聲明一個切面類 
  3.  * */  
  4. public class MyAspect {  
  5.       
  6.     public void before(){  
  7.         System.out.println("aspect before");  
  8.     }  
  9.   
  10.     public void afterReturning(){  
  11.         System.out.println("aspect afterReturning");  
  12.     }  
  13.       
  14. }  
結果:
[plain] view plain copy
  1. aspect before  
  2. Aspect biz  
  3. aspect afterReturning  
結果可以看出,后置通知會在業務方法的執行之后

5.1.3異常通知after-throwing

在方法拋出異常后的通知
配置文件: spring-aop-schema-advice.xml
[html] view plain copy
  1. <aop:config>  
  2. <!-- 切面類 -->  
  3.     <aop:aspect id="aspectTest" ref="myAspect">  
  4.     <!-- 切入點  標識切入點 aop包下類名以Biz結尾的類的所有方法-->  
  5.         <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>  
  6.         <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->  
  7.         <aop:before method="before" pointcut-ref="myPointcut"/>  
  8.         <!-- 返回之后的通知 -->  
  9.         <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>  
  10.         <!--  -->  
  11.         <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>  
  12.     </aop:aspect>  
  13. </aop:config>  
切面類:
[java] view plain copy
  1. /* 
  2.  * 聲明一個切面類 
  3.  * */  
  4. public class MyAspect {  
  5.       
  6.     public void before(){  
  7.         System.out.println("aspect before");  
  8.     }  
  9.   
  10.     public void afterReturning(){  
  11.         System.out.println("aspect afterReturning");  
  12.     }  
  13.       
  14.     public void afteThrowing(){  
  15.         System.out.println("aspect afteThrowing");  
  16.     }  
  17. }  

業務類:
修改為如下:
[java] view plain copy
  1. public void biz(){  
  2.     System.out.println("Aspect biz");  
  3.     throw new RuntimeException(); //出現異常的時候afteThrowing才會執行  
  4. }  

測試和結果:
[plain] view plain copy
  1. aspect before  
  2. Aspect biz  
  3. aspect afteThrowing   
  4. 上邊的結果由於拋出異常后,不會正常的返回所有沒有aspect afterReturning輸出  
 

5.1.4最終通知after(finally) advice 

不管方法是否會拋出異常都會通知,就像try...catch..finallly
配置文件: spring-aop-schema-advice.xml
[html] view plain copy
  1. <aop:config>  
  2. <!-- 切面類 -->  
  3.     <aop:aspect id="aspectTest" ref="myAspect">  
  4.     <!-- 切入點  標識切入點 aop包下類名以Biz結尾的類的所有方法-->  
  5.         <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>  
  6.         <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->  
  7.         <aop:before method="before" pointcut-ref="myPointcut"/>  
  8.         <!-- 返回之后的通知 -->  
  9.         <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>  
  10.         <!--  -->  
  11.         <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>  
  12.         <!-- after(finally) advice 不管是否拋出異常,最后都會執行的方法 -->  
  13.         <aop:after method="after" pointcut-ref="myPointcut"/>  
  14.     </aop:aspect>  
  15. </aop:config>  

切面類:
[java] view plain copy
  1. /* 
  2.  * 聲明一個切面類 
  3.  * */  
  4. public class MyAspect {  
  5.       
  6.     public void before(){  
  7.         System.out.println("aspect before");  
  8.     }  
  9.   
  10.     public void afterReturning(){  
  11.         System.out.println("aspect afterReturning");  
  12.     }  
  13.       
  14.     public void afteThrowing(){  
  15.         System.out.println("aspect afteThrowing");  
  16.     }  
  17.       
  18.     public void after(){  
  19.         System.out.println("aspect after(finally)");  
  20.     }  
  21. }  

業務類:
[html] view plain copy
  1. //業務類  
  2. public class AspectBiz {  
  3.       
  4.     public void biz(){  
  5.         System.out.println("Aspect biz");  
  6.         throw new RuntimeException();  
  7.     }  
  8. }  
測試結果:
[plain] view plain copy
  1. aspect before  
  2. Aspect biz  
  3. aspect afteThrowing  
  4. aspect after(finally)  
從結果中可以看出,拋出異常后,切面類中的after方法還是可以執行
 
[java] view plain copy
  1. 如果業務類如下:沒有異常,  
  2. public class AspectBiz {  
  3.     public void biz(){  
  4.         System.out.println("Aspect biz");  
  5.           
  6.     }  
  7.   
  8. }  
結果:
[plain] view plain copy
  1. aspect before  
  2. Aspect biz  
  3. aspect after(finally)  
 
由以上結果可以看到,不管怎么樣after方法還是會執行,很像try...catch..finally
 

5.1.5環繞通知around 

在方法的執行前后執行通知
配置文件: spring-aop-schema-advice.xml
[html] view plain copy
  1. <aop:config>  
  2. <!-- 切面類 -->  
  3.     <aop:aspect id="aspectTest" ref="myAspect">  
  4.     <!-- 切入點  標識切入點 aop包下類名以Biz結尾的類的所有方法-->  
  5.         <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>  
  6.         <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->  
  7.         <aop:before method="before" pointcut-ref="myPointcut"/>  
  8.         <!-- 返回之后的通知 -->  
  9.         <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>  
  10.         <!--  -->  
  11.         <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>  
  12.         <!-- after(finally) advice 不管是否拋出異常,最后都會執行的方法 -->  
  13.         <aop:after method="after" pointcut-ref="myPointcut"/>  
  14.         <!-- adroun advice 環繞通知,方法的第一參數必須是ProceedingJoinPoint類型 -->  
  15.         <aop:around method="around" pointcut-ref="myPointcut"/>  
  16.     </aop:aspect>  
  17. </aop:config>  

切面類:
可以看出,環繞方法的第一參數必須四ProceedingJoinPoint類型
[java] view plain copy
  1. /* 
  2.  * 聲明一個切面類 
  3.  * */  
  4. public class MyAspect {  
  5.       
  6.     public void before(){  
  7.         System.out.println("aspect before");  
  8.     }  
  9.   
  10.     public void afterReturning(){  
  11.         System.out.println("aspect afterReturning");  
  12.     }  
  13.       
  14.     public void afteThrowing(){  
  15.         System.out.println("aspect afteThrowing");  
  16.     }  
  17.       
  18.     public void after(){  
  19.         System.out.println("aspect after(finally)");  
  20.     }  
  21.       
  22.     public void around(ProceedingJoinPoint joinPoint){  
  23.         Object object = null;  
  24.         try{  
  25.             System.out.println("aspect around 1"); //方法執行前  
  26.             object = joinPoint.proceed();  //代表業務方法的執行  
  27.             System.out.println("aspect around 1"); //方法執行后  
  28.         }catch(Throwable e){  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32. }  

測試結果:
[plain] view plain copy
  1. aspect around 1  
  2. Aspect biz  
  3. aspect around 1  

從結果可以看出,joinPoint.proceed其實就是執行業務方法,我們可以在其之前做和之后做一些操作
 
5.1.6通知中的參數傳遞
這里我們列舉環繞通知中的參數參數傳遞,其他通知也是同樣的方式。
配置文件: spring-aop-schema-advice.xml
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.  xmlns:aop="http://www.springframework.org/schema/aop"  
  5.  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  6.  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">  
  7.       
  8.     <!-- 切面類 -->  
  9.     <bean id="myAspect" class="com.xxx.spring.aop.bean.annotation.aop.MyAspect"></bean>  
  10.       
  11.     <!-- 業務類 -->  
  12.     <bean id="aspectBiz" class="com.xxx.spring.aop.bean.annotation.aop.AspectBiz"></bean>  
  13.     <!-- aop配置 可以配置多個-->  
  14.     <aop:config>  
  15.     <!-- 切面類 -->  
  16.         <aop:aspect id="aspectTest" ref="myAspect">  
  17.         <!-- 切入點  標識切入點 aop包下類名以Biz結尾的類的所有方法-->  
  18.             <aop:pointcut expression="execution(* com.xxx.spring.aop.bean.annotation.aop.*Biz.*(..))" id="myPointcut"/>  
  19.             <!-- 通知 ,通過切入點切入切入切面類中的before方法 在執行切入點指定的方法之前執行 -->  
  20.             <aop:before method="before" pointcut-ref="myPointcut"/>  
  21.             <!-- 返回之后的通知 -->  
  22.             <aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>  
  23.             <!--  -->  
  24.             <aop:after-throwing method="afteThrowing" pointcut-ref="myPointcut"/>  
  25.             <!-- after(finally) advice 不管是否拋出異常,最后都會執行的方法 -->  
  26.             <aop:after method="after" pointcut-ref="myPointcut"/>  
  27.             <!-- adroun advice 環繞通知,方法的第一參數必須是ProceedingJjoinPoint類型 -->  
  28.             <!-- <aop:around method="around" pointcut-ref="myPointcut"/> -->  
  29.               
  30.             <!-- 參數傳遞  -->  
  31.             <aop:around method="aroundInit" pointcut="execution(* com.xxx.spring.aop.bean.annotation.aop.AspectBiz.init(String,int))  
  32.             and args(bizName,times)"/>  
  33.         </aop:aspect>  
  34.     </aop:config>  
  35. </beans>  

其中,通知中也可以單獨指定的pointcut,切入點中,我們單獨指定了init方法,且指定了方法的參數類型,和方法參數的名字,其中方法參數名字,可以更實際的方法參數名字不同,比如說init(String biz,int t) 都是可以匹配到的,不過為了維護方便,最好還是都一樣。
 
切面類:
[java] view plain copy
  1. /* 
  2.  * 聲明一個切面類 
  3.  * */  
  4. public class MyAspect {  
  5.       
  6.     public void before(){  
  7.         System.out.println("aspect before");  
  8.     }  
  9.   
  10.     public void afterReturning(){  
  11.         System.out.println("aspect afterReturning");  
  12.     }  
  13.       
  14.     public void afteThrowing(){  
  15.         System.out.println("aspect afteThrowing");  
  16.     }  
  17.       
  18.     public void after(){  
  19.         System.out.println("aspect after(finally)");  
  20.     }  
  21.       
  22.     public void around(ProceedingJoinPoint joinPoint){  
  23.         Object object = null;  
  24.         try{  
  25.             System.out.println("aspect around 1"); //方法執行前  
  26.             object = joinPoint.proceed();  //代表業務方法的執行  
  27.             System.out.println("aspect around 2"); //方法執行后  
  28.         }catch(Throwable e){  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32.       
  33.     //AOP中參數的傳遞  
  34.     public void aroundInit(ProceedingJoinPoint joinPoint,String bizName,int times){  
  35.         System.out.println(bizName+"--"+times);  
  36.         Object object = null;  
  37.         try{  
  38.             System.out.println("aspect around 1"); //方法執行前  
  39.             object = joinPoint.proceed();  //代表業務方法的執行  
  40.             System.out.println("aspect around 1"); //方法執行后  
  41.         }catch(Throwable e){  
  42.             e.printStackTrace();  
  43.         }  
  44.     }  
  45. }  

業務類:
[java] view plain copy
  1. public class AspectBiz {  
  2.       
  3.     public void biz(){  
  4.         System.out.println("Aspect biz");  
  5.     }  
  6.       
  7.     public void init(String bizName,int times){  
  8.         System.out.println("aspectBiz init:"+bizName+"  "+times);  
  9.     }  
  10.   
  11. }  

測試:
[java] view plain copy
  1. @Test  
  2. public void aspectAround(){  
  3.     ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/xxx/spring/chap4/spring-aop-schema-advice.xml");  
  4.     AspectBiz aspectBiz = (AspectBiz) ac.getBean("aspectBiz");  
  5.     aspectBiz.init("init", 3);  
  6. }  
測試結果:
[plain] view plain copy
  1. aspect before  
  2. init--3  
  3. aspect around 1  
  4. aspectBiz init:init  3  
  5. aspect around 1  
  6. aspect after(finally)  
  7. aspect afterReturning  
  8. AfterClass 標注的方法 會最后執行  
可以看到,參數比順利的傳送過去
 

6.Advisor

Advisor就像一個小的自包含,只有一個advice切面通過一個bean標識,並且必須實現一個advice接口,同時advisor也可以很好的利用aspectJ的切入點表達式Spring通過配置文件中 <aop:advisor>元素支持advisor實際使用中,大多數情況下它會和transactional advice配合使用,用於事務控制
配置文件使用案例:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:context="http://www.springframework.org/schema/context"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"  
  5.     xmlns:aop="http://www.springframework.org/schema/aop"  
  6.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  7.       
  8.      http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
  9.  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">  
  10.       
  11.     <bean name="sessionFactory"  
  12.         class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">  
  13.         <property name="configLocation">  
  14.             <!-- 路徑位於src下 -->  
  15.             <value>classpath:hibernate.cfg.xml</value>  
  16.         </property>  
  17.     </bean>  
  18.       
  19.     <!-- 事物配置 -->  
  20.     <bean id="txManager"  
  21.         class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
  22.         <property name="sessionFactory">  
  23.             <ref local="sessionFactory" />  
  24.         </property>  
  25.     </bean>  
  26.   
  27.     <!-- advisor配置 配置事務處理的Bean,定義切面(advice)   
  28.         由於getxxx,queryxxx,findxxx不涉及事務,可以設置read-only為true  
  29.     -->  
  30.     <tx:advice id="txAdvice" transaction-manager="txManager">  
  31.         <tx:attributes>  
  32.             <tx:method name="get*" read-only="true" />  
  33.             <tx:method name="query*" read-only="true" />  
  34.             <tx:method name="find*" read-only="true" />  
  35.             <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
  36.             <tx:method name="add*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
  37.             <tx:method name="del*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
  38.             <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
  39.             <tx:method name="*" propagation="REQUIRED" rollback-for="java.lang.Exception" />  
  40.         </tx:attributes>  
  41.     </tx:advice>  
  42.       
  43.     <!-- aop配置 -->  
  44.     <aop:config>  
  45.     <!-- 給impl包下的所有的方法配置adivce -->  
  46.         <aop:pointcut expression="excution(* com.xxx.spring.aop.bean.annotation.service.impl..(..))" id="serviceMethod" />  
  47.         <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod"  />  
  48.     </aop:config>  
  49.   
  50. </beans>  

關於spring的事務控制將會在另外一篇文章中介紹。
 

7.SpringAOP代理實現

這種實現方式,主要使用動態代理技術。 有接口的:使用JDK的動態里,無接口的:使用CGLIB代理
這種方式不是很常用
 

7.1.1ProxyFactoryBean

 
1.使用SpringAOP代理最關鍵的是使用org.springframework.aop.framework.ProxyFactoryBean,可以完全控制切入點和通知advice以及他們的順序
2.使用ProxyFacotryBean或者其他的IOC相關類來創建AOP代理的最重要的好處就是通知切入點可以由IOC來管理
3.被代理的類沒有實現任何接口,使用CGLIB代理,否者使用JDK代理
4.通過設置ProxyTargetClass為true可以強制使用CGLIB,(無論是否實現接口)
5.如果目標類實現了一個或者多個接口,那么創建代理的類型將依賴於ProxyFactoryBean的配置
6.如果ProxyFactoryBean的proxyInterfaces屬性被設置為一個或者多個全限定接口名,基於JDK的代理被創建
7.如果ProxyFactoryBean的proxyInterfaces屬性沒有被設置,但是目標類實現類一個或多個接口,那么ProxyFactoryBean將自動檢測到這個目標類已經實現了至少一個接口,創建一個基於JDK的代理
 
 

7.1.2使用代理實現環繞通知around

配置文件:
 
 
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="advice" class="com.xxx.spring.aop.bean.AdviceTest"></bean><!-- advice在方法執行前后添加我們的操作 -->  
  10.     <!-- 配置代理對象 -->  
  11.     <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  12.         <!--proxyInterfaces 如果ProxyFactoryBean的proxyInterfaces屬性沒有被設置,但是目標類實現類一個或多個接口,  
  13.         那么ProxyFactoryBean將自動檢測到這個目標類已經實現了至少一個接口,創建一個基於JDK的代理 -->  
  14.         <property name="proxyInterfaces" value="com.xxx.spring.aop.bean.UserDao"></property>  
  15.         <!-- 注入目標對象(注入被代理的對象) -->  
  16.         <property name="target" ref="target"></property>  
  17.         <!-- 注入代理對象所要執行的處理程序,通知配置 -->  
  18.         <property name="interceptorNames">  
  19.         <list>  
  20.             <value>advice</value>  
  21.         </list>  
  22.     </property>  
  23.     </bean>  
  24. </beans>  
 
注意:
上邊的<property name="proxyInterfaces" value="com.xxx.spring.aop.bean.UserDao">可以不用寫,Spring的ProxyFactoryBean將會自動檢測到
如果被代理的對象target實現了多個接口可以按照如下配置:
[html] view plain copy
  1. <property name="interfaces">  
  2.         <array>  
  3.             <value>com.xxx.spring.aop.bean.UserDao</value>  
  4.         </array>  
  5. </property>  
 
value中可以寫多個接口
 
同樣:通知interceptorNames如果只用一個通知可以寫成<property name="interceptorNames" name=" advice">
    如果有多個通知可以寫成:
[html] view plain copy
  1. <property name="interceptorNames">  
  2.         <list>  
  3.             <value>advice</value>  
  4.         </list>  
  5.     </property>  
但是 通知是不可以省略的,同時推薦結合的寫法
 
 
上邊的委托類即使普通的實現類:即ProxyFactoryBean被代理的對象
<bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>
 
上邊的通知配置
<bean name="advice" class="com.briup.spring.aop.bean.AdviceTest"></bean>

ProxyFactoryBean的配置
需要配置被代理的目標對象,通知,目標類實現的接口(可以省略,被ProxyFactoryBean自動識別
 
 
切面通知實現類
實現MethodInterceptor就可以實現環繞通知,我們可以在方法的目標對象類的方法執行前后加入處理邏輯
[java] view plain copy
  1. import java.util.Date;  
  2. import org.aopalliance.intercept.MethodInterceptor;  
  3. import org.aopalliance.intercept.MethodInvocation;  
  4.   
  5. public class AdviceTest implements MethodInterceptor{  
  6.   
  7.     @Override  
  8.     public Object invoke(MethodInvocation method) throws Throwable {  
  9.         System.out.println("方法開始執行"+new Date());  
  10.         method.proceed();  
  11.         System.out.println("方法執行完畢"+new Date());  
  12.         return null;  
  13.     }  
  14. }  
目標類:
[java] view plain copy
  1. //委托類  
  2. public class UserDaoImpl implements UserDao {  
  3.   
  4.     @Override  
  5.     public void saveUser() {  
  6.         System.out.println("保存用戶");  
  7.     }  
  8.   
  9.     @Override  
  10.     public void deleteUser() {  
  11.         System.out.println("刪除用戶");  
  12.     }  
  13.   
  14.     @Override  
  15.     public void updateUser() {  
  16.         System.out.println("更新用戶");  
  17.     }  
  18.   
  19. }  
接口:
[java] view plain copy
  1. public interface UserDao {  
  2.     public abstract void saveUser();  
  3.     public abstract void deleteUser();  
  4.     public abstract void updateUser();  
  5. }  
 
測試:
[java] view plain copy
  1. @Test  
  2. public void advice(){  
  3.     BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/advice.xml");      
  4.     UserDao userDao = factory.getBean("proxy", UserDao.class);  
  5.     userDao.saveUser();  
  6.     userDao.deleteUser();  
  7.     userDao.updateUser();  
  8. }  
測試結果:
[plain] view plain copy
  1. 方法開始執行Sun Sep 11 21:02:12 CST 2016  
  2. 保存用戶  
  3. 方法執行完畢Sun Sep 11 21:02:12 CST 2016  
  4. 方法開始執行Sun Sep 11 21:02:12 CST 2016  
  5. 刪除用戶  
  6. 方法執行完畢Sun Sep 11 21:02:12 CST 2016  
  7. 方法開始執行Sun Sep 11 21:02:12 CST 2016  
  8. 更新用戶  
  9. 方法執行完畢Sun Sep 11 21:02:12 CST 2016  

7.1.3使用動態代理實現前置通知before

配置文件:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="before" class="com.xxx.spring.aop.bean.BeforeTest"></bean>  
  10.     <!-- 配置代理對象 -->  
  11.     <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  12.         <!-- 注入目標對象(注入被代理的對象) -->  
  13.         <property name="target" ref="target"></property>  
  14.         <!-- 注入代理對象需要實現的所有接口 -->  
  15.         <property name="interfaces">  
  16.             <array>  
  17.                 <value>com.xxx.spring.aop.bean.UserDao</value>  
  18.             </array>  
  19.         </property>  
  20.         <!-- 注入代理對象所要執行的處理程序 -->  
  21.         <property name="interceptorNames">  
  22.             <array>  
  23.                 <value>before</value>  
  24.             </array>  
  25.         </property>  
  26.     </bean>  
  27. </beans>  

切面前置通知實現類:
實現MethodBeforeAdvice
[java] view plain copy
  1. import java.lang.reflect.Method;  
  2. import org.springframework.aop.MethodBeforeAdvice;  
  3. public class BeforeTest implements MethodBeforeAdvice{  
  4.   
  5.     @Override  
  6.     public void before(Method method, Object[] obj, Object object)  
  7.             throws Throwable {  
  8.         System.out.println("version 1.0 author tom "+method.getName()+" is execute");  
  9.     }  
  10.       
  11. }  

測試:
[java] view plain copy
  1. @Test  
  2. public void before(){  
  3.     BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/before.xml");      
  4.     UserDao userDao = factory.getBean("proxy", UserDao.class);  
  5.     userDao.saveUser();  
  6.     userDao.deleteUser();  
  7.     userDao.updateUser();  
  8. }  
 
結果:
[plain] view plain copy
  1. version 1.0 author tom saveUser is execute  
  2. 保存用戶  
  3. version 1.0 author tom deleteUser is execute  
  4. 刪除用戶  
  5. version 1.0 author tom updateUser is execute  
  6. 更新用戶  


7.1.4后置通知afterReturning

配置文件:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="after" class="com.xxx.spring.aop.bean.AfterTest"></bean>  
  10.     <!-- 配置代理對象 -->  
  11.     <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  12.         <!-- 注入目標對象(注入被代理的對象) -->  
  13.         <property name="target" ref="target"></property>  
  14.         <!-- 注入代理對象需要實現的所有接口 -->  
  15.         <property name="interfaces">  
  16.             <array>  
  17.                 <value>com.xxx.spring.aop.bean.UserDao</value>  
  18.             </array>  
  19.         </property>  
  20.         <!-- 注入代理對象所要執行的處理程序 -->  
  21.         <property name="interceptorNames">  
  22.             <array>  
  23.                 <value>after</value>  
  24.             </array>  
  25.         </property>  
  26.     </bean>  
  27. </beans>  

切面后置通知:
實現 AfterReturningAdivce接口
[java] view plain copy
  1. import java.lang.reflect.Method;  
  2. import org.springframework.aop.AfterReturningAdvice;  
  3. public class AfterTest  implements AfterReturningAdvice {  
  4.   
  5.     @Override  
  6.     public void afterReturning(Object arg0, Method arg1, Object[] arg2,  
  7.             Object arg3) throws Throwable {  
  8.         System.out.println(arg1.getName()+" is over!");  
  9.     }  
  10. }  
測試:
[java] view plain copy
  1. @Test  
  2. public void after(){  
  3.     BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/after.xml");   
  4.     UserDao userDao = factory.getBean("proxy", UserDao.class);  
  5.     userDao.saveUser();  
  6.     userDao.deleteUser();  
  7.     userDao.updateUser();  
  8. }  
測試結果:
[plain] view plain copy
  1. 保存用戶  
  2. saveUser is over!  
  3. 刪除用戶  
  4. deleteUser is over!  
  5. 更新用戶  
  6. updateUser is over!  

7.1.5異常通知throw

配置文件:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="throws" class="com.xxx.spring.aop.bean.ThrowsAdiviceTest"></bean>  
  10.     <!-- 配置代理對象 -->  
  11.     <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  12.         <!-- 注入目標對象(注入被代理的對象) -->  
  13.         <property name="target" ref="target"></property>  
  14.         <!-- 注入代理對象需要實現的所有接口 -->  
  15.         <property name="interfaces">  
  16.             <array>  
  17.                 <value>com.xxx.spring.aop.bean.UserDao</value>  
  18.             </array>  
  19.         </property>  
  20.         <!-- 注入代理對象所要執行的處理程序 -->  
  21.         <property name="interceptorNames">  
  22.             <list>  
  23.                 <value>throws</value>  
  24.             </list>  
  25.         </property>  
  26.     </bean>  
  27. </beans>  

異常通知切面:
參數中必須有Throwable的子類,前邊的參數 afterThrowing([Method, args, target], subclassOfThrowable)[]號中的參數可選
[java] view plain copy
  1. package com.briup.spring.aop.bean;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import org.springframework.aop.ThrowsAdvice;  
  6.   
  7. public class ThrowsAdiviceTest implements ThrowsAdvice{  
  8.   
  9.       
  10.     public void afterThrowing(Method method,Object[] args,Object target,Exception ex)throws Throwable{//Throwable subclass  
  11.         System.out.println("afterThrowing 2 ...."+method.getName()+"   "+ target.getClass().getName());  
  12.     }  
  13.   
  14. }  


測試:
[java] view plain copy
  1. @Test  
  2. public void throwTest(){  
  3.     BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/throw.xml");   
  4.     UserDao userDao = factory.getBean("proxy", UserDao.class);  
  5.     userDao.saveUser();  
  6.     userDao.deleteUser();  
  7.     userDao.updateUser();  
  8. }  
結果:
[plain] view plain copy
  1. 保存用戶  
  2. afterThrowing 2 ....saveUser   com.xxx.spring.aop.bean.UserDaoImpl  

7.1.6切入點配置pointcut

 
使用代理方式也可以配置切入點
NameMatchMethodPointcut,根據方法的名字進行匹配
mappedNames匹配的方法名集合
 
配置文件:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.briup.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="advice" class="com.xxx.spring.aop.bean.AdviceTest"></bean>  
  10.     <bean name="throws" class="com.xxx.spring.aop.bean.ThrowsAdiviceTest"></bean>  
  11.     <!-- 切入點 -->  
  12.     <bean name="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">  
  13.         <property name="mappedNames">  
  14.             <list>  
  15.                 <value>sa*</value>  
  16.             </list>  
  17.         </property>  
  18.     </bean>  
  19.     <!-- advisor -->  
  20.     <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
  21.         <property name="advice" ref="throws"></property>  
  22.         <property name="pointcut" ref="pointcutBean"></property>  
  23.     </bean>  
  24.     <!-- 配置代理對象 -->  
  25.     <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  26.         <!-- 注入目標對象(注入被代理的對象) -->  
  27.         <property name="target" ref="target"></property>  
  28.         <!-- 注入代理對象需要實現的所有接口 -->  
  29.         <property name="interfaces">  
  30.             <array>  
  31.                 <value>com.xxx.spring.aop.bean.UserDao</value>  
  32.             </array>  
  33.         </property>  
  34.         <!-- 注入代理對象所要執行的處理程序 -->  
  35.         <property name="interceptorNames">  
  36.             <list>  
  37.                 <value>defaultAdvisor</value>  
  38.                 <value>throws</value>  
  39.             </list>  
  40.         </property>  
  41.     </bean>  
  42. </beans>  

如上邊切入點配置:
[html] view plain copy
  1. <!-- 切入點 -->  
  2.   <bean name="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">  
  3.     <property name="mappedNames">  
  4.         <list>  
  5.             <value>sa*</value>  
  6.         </list>  
  7.     </property>  
  8.   </bean>  

切面:
[html] view plain copy
  1. <!-- advisor -->  
  2. <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
  3.     <property name="advice" ref="advice"></property>  
  4.     <property name="pointcut" ref="pointcutBean"></property>  
  5. </bean>  

7.1.7使用匿名的代理對象

使用匿名的代理對象可以將bean的配置到代理里邊,這樣就不用為target目標對象配置單獨的對象,這樣可以直接避免目標對象
配置文件:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  7.     <bean name="advice" class="com.xxx.spring.aop.bean.AdviceTest"></bean>  
  8.     <bean name="throws" class="com.xxx.spring.aop.bean.ThrowsAdiviceTest"></bean>  
  9.     <!-- 切入點 -->  
  10.     <bean name="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">  
  11.         <property name="mappedNames">  
  12.             <list>  
  13.                 <value>sa*</value>  
  14.             </list>  
  15.         </property>  
  16.     </bean>  
  17.     <!-- advisor -->  
  18.     <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">  
  19.         <property name="advice" ref="advice"></property>  
  20.         <property name="pointcut" ref="pointcutBean"></property>  
  21.     </bean>  
  22.     <!-- 配置代理對象 -->  
  23.     <bean name="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">  
  24.         <!-- 注入目標對象(注入被代理的對象),使用匿名的方式 -->  
  25.         <property name="target">  
  26.         <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  27.         </property>  
  28.         <!-- 注入代理對象需要實現的所有接口 -->  
  29.         <property name="interfaces">  
  30.             <array>  
  31.                 <value>com.xxx.spring.aop.bean.UserDao</value>  
  32.             </array>  
  33.         </property>  
  34.         <!-- 注入代理對象所要執行的處理程序 -->  
  35.         <property name="interceptorNames">  
  36.             <list>  
  37.                 <value>defaultAdvisor</value>  
  38.                 <value>throws</value>  
  39.             </list>  
  40.         </property>  
  41.     </bean>  
  42. </beans>  

7.1.8IntroductionInterceptor

Introduction是個特別的Advice,可以在不修改代碼的基礎上添加一些方法,可以參見
http://www.iteedu.com/webtech/j2ee/springdiary/35.php
http://go12345.iteye.com/blog/352745


8.自動代理實現

8.1.BeanNameAutoProxyCreator
 
Spring允許使用自動代理的bean定義,他可以自動代理選定bean,這樣我么就不用為代理對象聲明接口,或者沒有實現接口的時候,使用CGLIB代理
 
配置文件:
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="before" class="com.xxx.spring.aop.bean.BeforeTest"></bean>  
  10.     <!-- 配置代理對象 -->  
  11.      <bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">  
  12.         <!-- 注入需要被代理的對象名字,會代理所有以targ開始的bean -->  
  13.         <property name="beanNames">  
  14.             <list>  
  15.                 <value>targ*</value>  
  16.             </list>  
  17.         </property>  
  18.         <!-- 注入advice或者advisor -->  
  19.         <property name="interceptorNames">  
  20.             <list>  
  21.                 <value>before</value>  
  22.             </list>  
  23.         </property>  
  24.     </bean>  
  25. </beans>  
通過,自動代理,proxy會自動幫我們代理所有以targ開頭的目標委托類
 
實現類:
[java] view plain copy
  1. //委托類  
  2. public class UserDaoImpl implements UserDao {  
  3.     @Override  
  4.     public void saveUser(){  
  5.         System.out.println("保存用戶");  
  6.     }  
  7.       
  8.     @Override  
  9.     public void deleteUser() {  
  10.         System.out.println("刪除用戶");  
  11.     }  
  12.   
  13.     @Override  
  14.     public void updateUser() {  
  15.         System.out.println("更新用戶");  
  16.     }  
  17.   
  18. }  


 
測試:
[java] view plain copy
  1. @Test  
  2. public void autoAdvisor(){  
  3.     BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/autoAdvisor.xml");     
  4.     UserDao userDao = factory.getBean("target", UserDao.class);//autoAdvisor只能通過委托類的名字來拿  
  5.     userDao.saveUser();  
  6.     userDao.deleteUser();  
  7.     userDao.updateUser();  
  8. }  

結果:
[plain] view plain copy
  1. version 1.0 author tom saveUser is execute  
  2. 保存用戶  
  3. version 1.0 author tom deleteUser is execute  
  4. 刪除用戶  
  5. version 1.0 author tom updateUser is execute  
  6. 更新用戶  
8.2DefaultAdvisorAutoProxyCreator
使用DefaultAdvisorAutoProxyCreator我們可以不用顯示的指定advisor的bean定義 
 
[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5. http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">  
  6.     <!-- 配置委托類 -->  
  7.     <bean name="target" class="com.xxx.spring.aop.bean.UserDaoImpl"></bean>  
  8.     <!-- 配置代理對象將來執行的時候,所要執行的處理程序 -->  
  9.     <bean name="before" class="com.xxx.spring.aop.bean.BeforeTest"></bean>  
  10.     <!-- 配置advisor -->  
  11.     <!-- 作用:篩選要攔截的方法 -->  
  12.     <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
  13.         <!-- 注入advice -->  
  14.         <property name="advice" ref="before"></property>  
  15.         <!-- 注入需要被攔截的目標對象中的方法 -->  
  16.         <property name="patterns">  
  17.             <list>  
  18.                 <value>.*deleteUser</value>  
  19.             </list>  
  20.         </property>  
  21.     </bean>  
  22.       
  23.     <!-- 配置代理對象,當前IoC容器中自動應用,不用顯示應用advisor的bean定義 -->  
  24.     <bean name="proxy"  class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>  
  25. </beans>  
 
測試:
[java] view plain copy
  1. @Test  
  2. public void autoProxyByName(){  
  3.     BeanFactory factory = new ClassPathXmlApplicationContext("com/xxx/spring/chap2/autoProxyByName.xml");     
  4.     UserDao userDao = factory.getBean("target", UserDao.class);  
  5.     userDao.saveUser();  
  6.     userDao.deleteUser();  
  7.     userDao.updateUser();  
  8. }  

結果:
[java] view plain copy
  1. 保存用戶  
  2. version 1.0 author tom deleteUser is execute  
  3. 刪除用戶  
  4. 更新用戶  


參考文章:

http://blog.csdn.net/abcd898989/article/details/50809321

http://blog.csdn.net/peng658890/article/details/7223046

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM