AOP(Aspect Orient Programming ) , 面向切面編程 。
1、AOP的基本概念:
AOP框架並不與特定的代碼耦合,AOP框架能處理程序執行中特定的切入點(Pointcut),而不與具體某個類耦合。AOP框架具有如下特征:
1、各步驟之間的良好隔離性。
2、源代碼無關性。
AOP的專業術語:
1、Aspect(切面) : 應用運行過程中的關注點,關注點可以橫切多個對象,被稱為橫切關注點。
2、pointcut(切入點):可插入增強處理的連接點。
3、joinpoint(連接點):程序執行過程中明確的點,如方法的調用,或者異常的拋出。
4、advice(增強處理):AOP框架特定的切入點執行的增強處理
如何使用表達式來定義切入點:
1、引入:將方法或字段添加到被處理的類中。
2、目標對象:被AOP框架進行增強處理的對象,也被稱為被增強的對象。如果AOP框架是通過運行時代理來實現的,那么這個對象是一個被代理的對象。
3、AOP代理:AOP框架創建的對象,簡單的說,代理就是對目標對象的增強。
4、織入(Weaving):將增強處理添加到目標對象中,並創建一個被增強的處理的過程就是織入。
2、Spring的 AOP支持
在AOP編程,我們需要做如下三部分:
1、定義普通組件。
2、定義切入點、一個切入點可能橫切多個業務組件。
3、定義增強處理,增強處理就是在AOP框架為普通業務組件織入的處理動作。
AOP編成的關鍵是 定義切入點 和 定義增強處理,Spring依然有如下兩個方法來實現:
1、基於Annotation 的“零配置”方式。
2、使用XML配置文件的管理方式。
3、基於Annotation 的“零配置”方式
為了啟動Spring對@AspectJ切面配置的支持,並保證Spring容器中的目標Bean被一個或多個切面自動增強,必須在Spring配置文件下配置如下代碼:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 啟動@AspectJ支持--> <aop:aspectj-autoproxy /> </beans>
但是希望完全啟動Spring的“零配置”功能,則配置代碼中還需添加:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- 啟動@AspectJ支持--> <aop:aspectj-autoproxy /> </beans>
這里給出下面 增強處理的目標類:
package org.service.imp; import org.service.Person; import org.springframework.stereotype.*; @Component public class Chinese implements Person { public String sayHello(String name) { // TODO Auto-generated method stub return name + "你好 , Spring Aop"; } public void eat(String food) { // TODO Auto-generated method stub System.out.println("我正在吃:" + food) ; } }
3.1 定義切面Bean
在啟動@AspectJ 支持以后,只要在Sping 容器中配置一個帶@Aspect 注釋的Bean ,Spring將會自動識別該Bean,並將該Bean作為切面處理。
使用@Aspect標注一個Java類,該Java類將會作為切面Bean
@Aspect public class AspectTest {
//定義類的其他類容 ...... }
3.2 定義Before增強處理
使用@Before來標注一個方法,使該方法作為一個Before增強處理。使用@Before標注時,通常需要指定一個value值,改值指定一個切入表達式,用於指定該增強處理將被織入哪些切入點。
如:@Before("execution(* com.cnblogs.jbelial.*.*(..))")
在被它標注的方法將匹配com.cnblogs.jbelial包下的所有類的、所有方法的執行作為切入點。
如:
package org.advice.Before; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; //定義一個切面 @Aspect public class BeforeAdviceTest { //匹配該包下的所有類 @Before( "execution(* org.service.imp.*.*(..))") public void authority() { System.out.println("模擬執行權限檢查") ; } }
注:在定義增強處理時的Spring配置文件如何配置,可以參考Spring 的“零配置”支持“ 的學習。
3.3 定義AfterReturning增強處理
類似於使用@Before ,使用@AfterReturning 來標注一個增強處理,該增強處理將會在目標方法正常完成后被織入。在使用@AfterReturning Annotation時可以指定如下兩個常量屬性。
1、pointcut/value : 用於指定切入點對於的表達式。
2、returning :制定一個返回值形參名,增強處理定義的方法可以通過該形參名來訪問目標方法的返回值。
如:@AfterReturning(returning ="rvt" , pointcut = "execution(* com.cnblogs.jbelial.*.*(..))") ;
指定一個 returning 屬性,該屬性值為 rvt , 表示 允許在 增強處理方法中使用名為rvt的形參,該形參代表目標方法的返回值。
@AfterReturning Annotation 的 returning 屬性所制定的的形參名必須對應於增強處理中的一個形參名。當目標方法執行返回后,返回值作為相應的參數值傳入增強處理的方法。
如下:
package org.advice.AfterReturning; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; @Aspect public class AfterReturningAdivceTest { @AfterReturning( returning = "rvt" , pointcut = "execution(* org.service.imp.*.*(..))") public void log(Object rvt) { System.out.println("獲取目標方法返回值:"+rvt) ; System.out.println("模擬記錄日志功能...") ; } }
3.4 定義AfterThrowing 增強處理:
AfterThrowing 增強處理主要用於處理程序中未處理的異常。
@AfterThrowing Annotation 兩個常用的屬性:
> pointcut/value : 如上。
> throwing : 指定一個返回參數名,增強處理定義的方法可通過該形參名來訪問目標方法中所拋出的異常對象。
如:@AfterThrowing(throwing = "ex" ,pointcut = "execution(* com.cnblogs.jbelial.*.*(..))")
3.5 After 增強處理:
After 與 AfterReturning 的區別:
After : 增強處理不管目標方法如何結束,他都會被織入。因此,After 增強處理必須准備處理正常返回和異常返回兩種情況,這種增強處理通常用於釋放資源。
AfterReturning : 增強處理只有在目標方法成功完成才會被織入。
如下:
package org.advice.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.After; @Aspect public class AfterAdviceTest { @After ("execution(* org.service.imp.*.*(..))") public void release() { System.out.println("模擬方法結束后的釋放資源...."); } }
3.6 Around 增強處理 :
Around 增強處理既可以在執行目標方法之前織入增強處理,可以在執行目標方法之后織入增強動作。同時,Around 增強處理甚至可以決定目標方法在什么時候執行,如何執行,甚至可以完全阻止目標方法的執行。
Around 增強處理可以改變執行目標方法的參數值,也可以改變執行目標方法之后的返回值。
當定義一個 Around 增強處理方法時,該方法的第一個形參必須是 ProceedingJoinPoint 類型,調用 ProceedingJoinPoint 的 proceed() 方法才會執行目標方法。
如下:
package org.advice.Around; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; @Aspect public class AroundAdviceTest { @Around ( "execution(* org.service.imp.*.*(..))") public void processText(ProceedingJoinPoint PJ) throws Throwable { System.out.println("執行目標方法之前,模擬開始事務。"); PJ.proceed() ; System.out.println("執行目標方法之后,模擬結束事務。"); } }
3.7 訪問目標方法的參數:
訪問目標方法的做法是定義增強處理時將第一個參數定義為JoinPoint 類型,當該增強處理方法被調用時,該JoinPoint 參數就代表了織入增強處理的連接點。該JoinPoint 里包含了如下常用的方法:
> Object[] getArgs() : 返回執行目標方法時的參數。
> Signature getSignature() : 返回被增強的方法的相關信息。
> Object getTarget() : 返回被織入增強處理的目標對象。
> Object getThis() : 返回AOP框架為目標的相關信息。
注意:ProceedingJoinPoint 該類是JoinPoint 的子類。
3.8 定義切入點:
為一個切入表達式起一個名稱,從而允許在多個增強處理中重用該名稱。Spring AOP 只支持以Spring Bean 的方法執行組 作為連接點,所以可以把切入點看錯所有能和切入表達式匹配的Bean 方法。
切入點定義包含兩個部分:
> 一個切入點表達式。
> 一個包含名字和任意參數的方法簽名。
如下:
package org.advice.AfterReturning; import org.aspectj.lang.annotation.*; @Aspect public class adviceExpression { @Pointcut("execution(* org.service.imp.*.*(..))") public void test() { } }
注意:上面代碼中的 test方法的返回值必須是void , 且當用private 訪問控制符修飾時,則僅能在切面類中使用該切入點。
package org.advice.AfterReturning; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; @Aspect public class AfterReturningAdivceTest { @AfterReturning( returning = "rvt" , pointcut = "adviceExpression.test()") public void log(Object rvt) { System.out.println("獲取目標方法返回值:"+rvt) ; System.out.println("模擬記錄日志功能...") ; } }
3.9 切入點指示符
Spring AOP 僅僅支持部分 Aspect J 的切入指示符。
Spring AOP 支持的切入點指示符有:
> exection : 用於匹配執行方法的連接點,
> within : 限定匹配特定類型的連接點,當使用Spring AOP 的時候,只能匹配方法執行的連接點。
如下:
within(org.service.imp.*) // imp 包中的任意連接點
within(org.service.imp..*) // imp 包或子包中的任意連接點
> this : 用於限定AOP 代理必須是指定類型的實例,用於匹配該對象的所有連接點。當使用Spring AOP 的時候,只能匹配方法執行的連接點。
> target : 用於限定目標對象必須是指定類型的實例,用於匹配該對象的所有連接點。當使用Spring AOP 的時候,只能匹配方法執行的連接點。
如下:
// 匹配實現了Person 接口的目標對象的所有連接
// 在Spring AOP 中只是方法執行的連接點
target(org.service.imp.Person)
> args : 用於對限定目標參數類型的限定,要求參數類型是指定類型的實例。當使用Spring AOP 的時候,只能匹配方法執行的連接點。
Spring 支持使用如下路基運算符來組合切入點表達式。
> !! : 只要連接點匹配任意一個切入點表達式。
> && :
> ! : 要求連接點不匹配指定切入點表達式。