天天看點

[Spring實戰系列](16)面向切面程式設計(AOP)概述

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。 https://blog.csdn.net/SunnyYoona/article/details/50651781

1. 簡介

在軟體中,有些行為對于大多數應用都是通用的。日志,安全和事務管理的确很重要,但他們是都是應用對象主動參與的行為呢?如果讓應用對象隻關注自己所針對的業務領域問題,而其他方面的問題由其他應用對象來處理,這樣會不會更好?

在軟體開發中,分布于應用中多處的功能被稱為橫切關注點。通常,這些橫切關注點從概念上是與應用的業務邏輯相分離的(但是往往直接嵌入到應用的業務邏輯中)。将這些橫切關注點與業務邏輯相分離是面向切面程式設計索要解決的。

上圖展示了一個被劃分為子產品的典型應用。每個子產品的核心功能都是為特定業務領域提供服務,但是這些子產品都需要類似的輔助功能,例如安全和事務管理。

繼承與委托是最常見的實作重用通用功能的面向對象技術。但是,如果在整個應用中使用相同的基類,繼承往往會導緻一個脆弱的對象體系;而使用委托可能需要委托對象進行複雜的調用。切面提供了取代繼承與委托的另一種選擇。在使用面向切面程式設計時,我們讓然在一個地方定義通用功能,但是我們可以通過聲明的方式定義這個功能以何種方式在何處應用,而無需修改受影響的類。

2. 幾個AOP概念

描述AOP功能的術語并不直覺,在這共同學習一下。

2.1 通知

在AOP術語中,切面的工作被稱為通知。通知定義了切面是什麼以及何時使用。除了描述切面要完成的工作,通知還解決了何時執行這個工作的問題。它該應用與某個方法被調用之前?之後?

類型 說明
Before 在方法被調用之前調用通知。
After 在方法完成之後調用通知,無論方法執行是否成功。
After-returning 在方法成功執行之後調用通知。
After-throwing 在方法抛出異常後調用通知。
Around 通知包裹了被通知的方法,在被通知的方法調用之前和調用之後執行自定義的行為。
2.2 連接配接點

連接配接點是在應用執行過程中能夠插入切面的一個點。這個點可以是調用方法時,抛出異常時,甚至修改一個字段時。切面代碼可以利用這些點插入到應用的正常流程之中,并添加新的行為

2.3 切點

一個切面并不需要通知應用的所有連接配接點。切點有助于縮小切面所通知連接配接點的範圍。

2.4 切面

切面是通知和切點的結合。通知和切點共同定義了關于切面的全部内容-----它是什麼,在何時和在何處完成其功能。

2.5 引入

引入允許我們向現有的類添加新方法或屬性。例如,我們可以建立一個Auditable通知類,該類記錄了對象最後一次修改時的狀态。我們隻需一種方法,setLastModified(Date),和一個執行個體變量來儲存這個狀态。然後,這個新方法和執行個體變量就可以被引入到現有的類中。進而可以在無需修改這些現有的類的情況下,讓他們具有新的行為和狀态。

2.6 織入

織入是将切面應用到目标對象來建立新的代理對象的過程。切面在指定的連接配接點被織入到目标對象中。在目标對象的生命周期裡有多個點可以進行織入。

3. Spring對AOP的支援

并不是所有的AOP架構都是一樣的,盡管有些不同,但是無論如何,建立切點來定義切面織入的連接配接點是AOP架構的基本功能。

現在主要的AOP架構:

  • AspecJ
  • JBoss AOP
  • Spring AOP

在這裡我們主要看Spring對AOP的支援,Spring提供了4種各具特色的AOP支援:

  • 基于代理的經典AOP
  • @AspectJ注解驅動的切面
  • 純POJO切面
  • 注入式AspectJ切面(适合Spring各版本)
3.1 Spring通知是Java編寫的

Spring所建立的通知都是用标準的Java類編寫的。這樣的話,我們就可以使用與普通Java開發一樣的內建開發環境(IDE)來開發切面。而且,定義通知所應用的切點通常在Spring配置檔案裡采用XML來編寫的。AspectJ與之相反,雖然AspectJ現在支援基于注解的切面,但是AspectJ最初是以Java語言擴充的方式實作的。這種方式既有優點也有缺點。通過特有的AOP語言,我們可以獲得更強大和細粒度的控制,以及更豐富的AOP工具集,但是需要我們學習額外的新工具和文法。

3.2 Spring在運作期通知對象

通過在代理類中包裹切面,Spring在運作期将切面織入到Spring管理的Bean中。代理類封裝了目标類,并攔截被通知的方法的調用,再将調用轉發給真正的目标Bean。

當攔截到方法調用時,在調用目标Bean方法之前,代理會執行切面邏輯。知道應用需要被代理的Bean時,Spring才建立代理對象。如果使用的是ApplicationContext,在ApplicationContext從BeanFactory中加載所有的Bean時,Spring建立被代理的對象。因為Spring運作時才建立代理對象,是以我們不需要對特殊的編譯器來織入Spring AOP的切面。

3.3 Spring隻支援方法連接配接點

因為Spring是基于動态代理的,是以Spring隻支援方法連接配接點。這與其他一些AOP架構是不同的,例如AspectJ和JBoss,除了方法切點,它們還提供字段和構造器接入點。Spring缺少字段連接配接點的支援,無法建立更細粒度的通知,例如攔截對象字段的修改,而且Spring也不支援構造器連接配接點,我們也無法在Bean建立時應用通知。

來源于:《Spring實戰》