Spring中AOP實現

1.什麼是SpringAOP

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

2.SpringAOP框架的用途

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

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

3.AOP的實現方式

下邊這兩種Spring都是支持的

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

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

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

Spring沒有使用AspectJ的時候,也能夠經過以下方式實現AOPweb

Spring AOP 默認使用標準的JavaSE動態代理做爲AOP代理,這使得任何接口(或者集合)均可以被代理
Spring AOP 中也可使用CGLIB代理(若是一個業務對象沒有實現一個接口)
有接口的:使用JDK的動態裏
無接口的:使用CGLIB代理
spring

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()是最經常使用的切點函數,其語法以下所示:
 整個表達式能夠分爲五個部分:
 一、execution(): 表達式主體。
 二、第一個*號:表示返回類型,*號表示全部的類型。
 三、包名:表示須要攔截的包名,後面的兩個句點表示當前包和當前包的全部子包,com.sample.service.impl包、子孫包下全部類的方法。
 四、第二個*號:表示類名,*號表示全部的類。
 五、*(..):最後這個星號表示方法名,*號表示全部的方法,後面括弧裏面表示方法的參數,兩個句點表示任何參數。
 
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通用的,其餘方式能夠本身查找資料express

 

推薦:編程

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

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

 

5.SpringAOP實現

上邊的一些概念,看事後可能仍是不懂,能夠自行查閱資料,下邊我也會說明

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

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

相關文章
相關標籤/搜索