spring-aop切面知識


一、AOP的概念

AOP(Aspect Oriented Programming),即為面向切面編程。在軟件開發中,散布於應用中多處的

功能被稱為橫切關注點(cross-cutting concern),通常來說,這些橫切關注點從概念上是與應用的業務

邏輯分離的。比如,聲明式事務、日志、安全、緩存等等,都與業務邏輯無關,可以將這些東西抽象成

為模塊,采用面向切面編程的方式,通過聲明方式定義這些功能用於何處,通過預編譯方式和運行期動

態代理實現這些模塊化橫切關注點程序功能進行統一維護,從而將橫切關注點與它們所影響的對象之

間分離出來,就是實現解耦。

橫切關注點可以被模塊化為特殊的類,這些類被稱為切面(aspect)。這樣做有兩個優點:

1)每個關注點都集中於一個地方,而不是分散到多處代碼中;

2)服務模塊更簡潔,因為它們只包含主要的關注點的代碼(核心業務邏輯),

而次要關注點的代碼(日志,事務,安全等)都被轉移到切面中。

通知(Advice)

切面類有自己要完成的工作,切面類的工作就稱為通知。通知定義了切面是做什么以及何時使用。

"做什么",即切面類中定義的方法是干什么的;

"何時使用",即5種通知類型,是在目標方法執行前,還是目標方法執行后等等;

"何處做",即通知定義了做什么,何時使用,但是不知道用在何處,而切點定義的就是告訴通知應該用在

哪個類的哪個目標方法上,從而完美的完成橫切點功能。

Spring切面定義了5種類型通知:

1)前置通知(Before):在目標方法被調用之前調用通知功能。

2)后置通知(After):在目標方法完成之后調用通知,不會關心方法的輸出是什么。

3)返回通知(After-returning): 在目標方法成功執行之后調用通知。

4)異常通知(After-throwing):在目標方法拋出異常后調用通知。

5)環繞通知(Around):通知包裹了被通知的方法,在被通知的方法調用之前和之后執行自定義的行為。

切面(Aspect)

切面是通知和切點的結合,通知和切點共同定義了切面的全部內容。因為通知定義的是切面的

"要做什么"和"在何時做",而切點定義的是切面的"在何地做"。將兩者結合在一起,就可以完美的

展現切面在何時,何地,做什么(功能)。

連接點(Join point)

即被通知的類中的方法都可能成為切點,所以這些都是連接點,定義成切點之后,這個連接點就變成了切點,通知的類可能是一個類,也有可能是一個包底下的所有類,所以連接點可以成千上萬來記,是一個虛概念,可以把連接點看成是切點的集合。

切點(Poincut)

在被通知的類上,連接點談的是一個飄渺的大范圍,而切點是一個具體的位置,用於縮小切面所通知的連接點的范圍。

前面說過,通知定義的是切面的"要做什么"和"在何時做",是不是沒有去哪里做,而切點就定義了"去何處做"。

切點的定義會匹配通知所要織入的一個或多個連接點。我們通常使用明確的類和方法名稱,或者是使用

正則表達式定義所匹配的類和方法名稱來指定切點。說白了,切點就是讓通知找到"發泄的地方"。

引入(Introduction)

引入這個概念就比較高大尚,引入允許我們向現有的類添加新方法或屬性。

主要目的是想在無需修改A的情況下,引入B的行為和狀態。

織入(Weaving)

織入是把切面應用到目標對象並創建新的代理對象的過程。切面在指定的連接點被織入到目標對象中。

在目標對象的生命周期里有多個點可以進行織入:

編譯期: 

    切面在目標類編譯時被織入。需要特殊的編譯器,是AspectJ的方式,不是spring的菜。

類加載期: 

    切面在目標類加載到JVM時被織入。這種方式需要特殊的類加載器,它可以在目標類被引入應用之前

    增強該目標類的字節碼。AspectJ5支持這種方式。

運行期:  

     切面在應用運行的某個時刻被織入。一般情況下,在織入切面時,AOP容器會為目標對象動態的創建

     一個代理對象。而這正是Spring AOP的織入切面的方式。

AOP實戰(注解版)

1、創建切面類

切面類包含通知和切入點,在創建切面類之前,我們需要了解下AspectJ的切點表達式,因為我們需要通過

切點表達式定義切點,用於准確的定位應該在什么地方應用切面的通知。

 

 

 

2、創建目標類,定義目標方法

用@Configuration代替xml方式啟動容器

/**

 * Jdk代理:基於接口的代理,一定是基於接口,會生成目標對象的接口的子對象。

 * Cglib代理:基於類的代理,不需要基於接口,會生成目標對象的子對象。

 * 1. 注解@EnableAspectJAutoProxy開啟代理;

 * 2. 如果屬性proxyTargetClass默認為false, 表示使用jdk動態代理織入增強;

 * 3. 如果屬性proxyTargetClass設置為true,表示使用Cglib動態代理技術織入增強;

 * 4. 如果屬性proxyTargetClass設置為false,但是目標類沒有聲明接口,

 *    Spring aop還是會使用Cglib動態代理,也就是說非接口的類要生成代理都用Cglib。

 */

利用spring測試類測試

 

 到此,我們基本上了解了基於注解的AOP實戰。

環繞通知

關於通知類型,需要單獨分析的是環繞通知,他跟其他通知類型不一樣,環繞通知也是最為強大的一種通知方式,

所謂的環繞通知,顧名思義,它能夠讓你所編寫的邏輯將被通知的目標方法全部包裝起來。

實際上就像我們前面寫的開會前,開會后干的哪些事情,對於環繞通知來說,一個方法就搞定了,因為他包圍了目標方法,

等同於在一個通知方法中同時編寫了前置通知和后置通知,環繞通知都會為執行開會前,開會后等等邏輯。

 

 

原文出自:https://i.cnblogs.com/EditPosts.aspx?opt=1

 

 

 

 

 

@Aspect@Componentpublic class LoggingAspect {
@Before("execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomer(..))")public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("hijacked : " + joinPoint.getTarget());System.out.println("******");}
@After("execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomer(..))")public void logAfter(JoinPoint joinPoint) {System.out.println("******");System.out.println("logAfter() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("******");
}@AfterReturning(pointcut="execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomerReturnValue(..))", returning= "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("logAfterReturning() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("Method returned value is : " + result);System.out.println("******");
}@AfterThrowing(pointcut="execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomerThrowException(..))",throwing="error")public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
System.out.println("logAfterThrowing() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("Exception : " + error);System.out.println("******");
}@Around("execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomerAround(..))")public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("logAround() is running!");System.out.println("hijacked method : " + joinPoint.getSignature().getName());System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));System.out.println("Around before is running!");joinPoint.proceed();System.out.println("Around after is running!");System.out.println("******");
}


免責聲明!

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



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