Spring AOP

1 篇文章 / 0 new
author
Spring AOP
AOP全名 Aspect-oriented programming 側面導向程式
AOP實現的關鍵在於AOP框架自動創建的AOP代理,AOP代理主要分為靜態代理和動態代理:
• 以AspectJ實現靜態代理
所謂靜態代理就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強。ApsectJ是靜態代理的實現之一,也是最為流行的。靜態代理由於在編譯時就生成了代理類,效率相比動態代理要高一些。AspectJ可以單獨使用,也可以和Spring結合使用。

• 以Spring AOP實現動態代理
與靜態代理不同,動態代理就是說AOP框架不會去修改編譯時生成的字節碼,而是在運行時在內存中生成一個AOP代理對象,這個AOP對象包含了目標對象的全部方法,並且在特定的切點做了增強處理,並回調原對象的方法。

AOP透過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術,是OOP面向對象編程的一種補足。它是軟體開發中的一個熱點技術,Spring AOP 也是Spring框架的核心特性之一(另一個核心特性是IOC)

通過AOP技術,我們希望實現一種通用邏輯的解耦,解決一些系統層面上的問題,如日誌、事務、權限等,從而提高應用的可重用性和可維護性,和開發效率

重要概念
AOP中包括 5 大核心概念:切面(Aspect), 切入點(Pointcut), 連接點(JoinPoint), 通知(Advice), AOP代理(Proxy)。(記憶口訣:通知 代理 廚師兩點(切入點, 連接點)切面包)

AOP代理
是AOP框架如Spring AOP創建的對象,代理就是對目標對象進行增強,Spring AOP中的代理默認使用JDK動態代理,同時支持CGLIB代理,前者基於接口,後者基於子類。在Spring AOP中,其功能依然離不開IOC容器,代理的生成、管理以及其依賴關係都是由IOC容器負責,目前大多使用JDK動態代理。JDK代理通過反射來處理被代理的類,並且要求被代理類必須實現一個接口。核心類是 InvocationHandler接口 和 Proxy類。而當目標類沒有實現接口時,Spring AOP框架會使用CGLIB來動態代理目標類。

CGLIB(Code Generation Library),是一個代碼生成的類庫,可以在運行時動態的生成某個類的子類。CGLIB是通過繼承的方式做的動態代理,因此如果某個類被標記為final,那麼它是無法使用CGLIB做動態代理的。核心類是 MethodInterceptor 接口和Enhancer 類

切面(Aspect) : 使用 @Aspect 註解的類就是切面, 配合@Order可調整觸發優先權, 值越小越優先
@Component
@Aspect
public class LogAspect {
}

切入點(PointCut) : 切入點是對連接點進行攔截的條件定義
切入點表達式如何和連接點匹配是AOP的核心,Spring預設使用AspectJ切入點語法。切入點的作用就是提供一組規則(使用 AspectJ pointcut expression language 來描述)來匹配連接點,滿足規則則發通知給連接點。
@Pointcut("execution(* com.shioulo.test.service..*(..))")
public void pointcut() { }
範例切入點的匹配規則是指向 com.shioulo.test.service包下的所有類的所有函數
♦ 匹配方法
//匹配由指定註解所標註的方法
@annotation(com.xys.AuthChecker)
// 匹配指定包中的所有的方法
execution(* com.xys.service.*(..))
// 匹配當前包中的指定類的所有方法
execution(* UserService.*(..))
// 匹配指定包中的所有 public 方法
execution(public * com.xys.service.*(..))
// 匹配指定包中的所有 public 方法, 並且返回值是 int 型別的方法
execution(public int com.xys.service.*(..))
// 匹配指定包中的所有 public 方法, 並且第一個引數是 String, 返回值是 int 型別的方法
execution(public int com.xys.service.*(String name, ..))
匹配型別簽名
// 匹配指定包中的所有的方法, 但不包括子包
within(com.xys.service.*)
// 匹配指定包中的所有的方法, 包括子包
within(com.xys.service..*)
// 匹配當前包中的指定類中的方法
within(UserService)
// 匹配一個介面的所有實現類中的實現的方法
within(UserDao )
匹配 Bean 名字
// 匹配以指定名字結尾的 Bean 中的所有方法
bean(*Service)
切點表示式組合
// 匹配以 Service 或 ServiceImpl 結尾的 bean
bean(*Service || *ServiceImpl)
// 匹配名字以 Service 開頭, 並且在包 com.xys.service 中的 bean
bean(*Service) && within(com.xys.service.*)

通知(Advice) : Spring AOP框架以攔截器來實現通知模型,並維護一個以連接點為中心的攔截器鏈
@Before("pointcut()")<br />
public void log(JoinPoint joinPoint) {<br />
}

五大通知類型:
1、前置通知 [ Before advice ] :在連接點前面執行,前置通知不會影響連接點的執行,除非此處拋出異常
2、正常返回通知 [ After returning advice ] :在連接點正常執行完成後執行,如果連接點拋出異常,則不會執行
3、異常返回通知 [ After throwing advice ] :在連接點拋出異常後執行
4、返回通知 [ After (finally) advice ] :在連接點執行完成後執行,不管正常執行完成,還是拋出異常,都會執行返回通知中的內容
5、環繞通知 [ Around advice ] :環繞通知圍繞在連接點前後,比如一個方法調用的前後。這種通知是最強大的通知,能在方法調用前後自定義一些操作

參數匹配
// 匹配只有一個引數 name 的方法
@Before(value = "aspectMethod() && args(name)")
public void do1(String name) {}
// 匹配第一個引數為 name 的方法
@Before(value = "aspectMethod() && args(name, ..)")
public void do2(String name) {}
// 匹配第二個引數為 name 的方法
Before(value = "aspectMethod() && args(*, name, ..)")
public void do3(String name) {}

各類型通知執行先後順序 Arount > Before > method > AfterReturning / AfterThrowing > After

Aspect1 和Aspect2兩個切面類中所有通知類型的執行順序,Method是具體的切入點,order代表優先級,它根據一個int值來判斷優先級的高低,數字越小,優先級越高, 且@Around是先於@Before執行
 
織入(Weaving)
織入是將切面和業務邏輯對象連接起來, 並創建通知代理的過程。織入可以在編譯時,類加載時和運行時完成。在編譯時進行織入就是靜態代理,而在運行時進行織入則是動態代理。

► 增強器(Adviser)
Advisor是切面的另外一種實現,能夠將通知以更為複雜的方式織入到目標對象中,是將通知包裝為更複雜切面的裝配器。Advisor由切入點和Advice組成。

Advisor這個概念來自於Spring對AOP的支撐,在AspectJ中是沒有等價的概念的。Advisor就像是一個小的自包含的切面,這個切面只有一個通知。切面自身通過一個Bean表示,並且必須實現一個默認接口。

 


from Spring AOP, Spring AOP, Spring AOP概念,
Free Web Hosting