只有光頭才能變強
上一篇已經講解了Spring IOC知識點一網打盡!,這篇主要是講解Spring的AOP模塊~java
以前我已經寫過一篇關於AOP的文章了,那篇把比較重要的知識點都講解過了一篇啦:Spring【AOP模塊】就這麼簡單,很榮幸被開源中國推薦過~~spring
這篇文章主要是補充和強化一些比較重要的知識點,並會把上面的兩本書關於AOP的知識點整理出來並畫成一個思惟導圖來全面瞭解Spring AOP的知識點!編程
那麼接下來就開始吧,若是有錯的地方但願能多多包涵,並不吝在評論區指正!微信
結合《Spring 實戰 (第4版)》和《精通Spring4.x 企業應用開發實戰》兩本書的AOP章節將其知識點整理起來~編輯器
AOP稱爲面向切面編程,那咱們怎麼理解面向切面編程??post
咱們能夠先看看下面這段代碼:性能
咱們學Java面向對象的時候,若是代碼重複了怎麼辦啊??能夠分紅下面幾個步驟:測試
抽取成類的方式咱們稱之爲:縱向抽取spa
可是,咱們如今的辦法不行:即便抽取成類仍是會出現重複的代碼,由於這些邏輯(開始、結束、提交事務)依附在咱們業務類的方法邏輯中!翻譯
如今縱向抽取的方式不行了,AOP的理念:就是將分散在各個業務邏輯代碼中相同的代碼經過橫向切割的方式抽取到一個獨立的模塊中!
上面的圖也很清晰了,將重複性的邏輯代碼橫切出來其實很容易(咱們簡單可認爲就是封裝成一個類就行了),但咱們要將這些被咱們橫切出來的邏輯代碼融合到業務邏輯中,來完成和以前(沒抽取前)同樣的功能!這就是AOP首要解決的問題了!
被咱們橫切出來的邏輯代碼融合到業務邏輯中,來完成和以前(沒抽取前)同樣的功能
沒有學Spring AOP以前,咱們就可使用代理來完成。
其實Spring AOP的底層原理就是動態代理!
來源《精通Spring4.x 企業應用開發實戰》一段話:
Spring AOP使用純Java實現,它不須要專門的編譯過程,也不須要特殊的類裝載器,它在 運行期經過代理方式向目標類織入加強代碼。在Spring中能夠無縫地將Spring AOP、IoC和AspectJ整合在一塊兒。
來源《Spring 實戰 (第4版)》一句話:
Spring AOP構建在動態代理基礎之上,所以, Spring對AOP的支持侷限於方法攔截。
在Java中動態代理有兩種方式:
JDK動態代理是須要實現某個接口了,而咱們類未必所有會有接口,因而CGLib代理就有了~~
那麼JDK代理和CGLib代理咱們該用哪一個呢??在《精通Spring4.x 企業應用開發實戰》給出了建議:
緣由:
看到這裏咱們就應該知道什麼是Spring AOP(面向切面編程)了:將相同邏輯的重複代碼橫向抽取出來,使用動態代理技術將這些重複代碼織入到目標對象方法中,實現和原來同樣的功能。
AOP除了有Spring AOP實現外,還有著名的AOP實現者:AspectJ,也有可能你們沒據說過的實現者:JBoss AOP~~
咱們下面來講說AspectJ擴展一下知識面:
AspectJ是 語言級別的AOP實現,擴展了Java語言,定義了AOP語法,可以在 編譯期提供橫切代碼的織入,因此它有 專門的編譯器用來生成遵照Java字節碼規範的Class文件。
而Spring借鑑了AspectJ不少很是有用的作法,融合了AspectJ實現AOP的功能。但Spring AOP本質上底層仍是動態代理,因此Spring AOP是不須要有專門的編輯器的~
嗯,AOP搞了好幾個術語出來~~兩本書都有講解這些術語,我會盡可能讓你們看得明白的:
鏈接點(Join point):
切點(Poincut):
加強/通知(Advice):
表示添加到切點的一段邏輯代碼,並定位鏈接點的方位信息。
織入(Weaving):
加強/通知
添加到目標類的具體鏈接點上的過程。引入/引介(Introduction):
引入/引介
容許咱們向現有的類添加新方法或屬性。是一種特殊的加強!切面(Aspect):
加強/通知
組成,它既包括了橫切邏輯的定義、也包括了鏈接點的定義。在《Spring 實戰 (第4版)》給出的總結是這樣子的:
通知/加強包含了須要用於多個應用對象的橫切行爲;鏈接點是程序執行過程當中可以應用通知的全部點;切點定義了通知/加強被應用的具體位置。其中關鍵的是切點定義了哪些鏈接點會獲得通知/加強。
總的來講:
Spring提供了3種類型的AOP支持:
基於代理的經典SpringAOP
純POJO切面
@AspectJ
註解驅動的切面
這部分配置比較麻煩,用起來也很麻煩,這裏我就主要整理一下書上的內容,你們看看了解一下吧,咱們實際上使用Spring AOP基本不用這種方式了!
首先,咱們來看一下加強接口的繼承關係圖:
能夠分紅五類加強的方式:
Spring提供了六種的切點類型:
切面類型主要分紅了三種:
通常切面,切點切面,引介/引入切面介紹:
對於切點切面咱們通常都是直接用就行了,咱們來看看引介/引入切面是怎麼一回事:
繼承關係圖:
引介/引入切面有兩個實現類:
實際上,咱們使用AOP每每是Spring內部使用BeanPostProcessor幫咱們建立代理。
這些代理的建立器能夠分紅三類:
對應的類繼承圖:
嗯,基於代理的經典SpringAOP就講到這裏吧,其實我是不太願意去寫這個的,由於已經幾乎不用了,在《Spring 實戰 第4版》也沒有這部分的知識點了。
Spring在新版本中對AOP功能進行了加強,體如今這麼幾個方面:
那咱們使用@AspectJ
來玩AOP的話,學什麼??其實也就是上面的內容,學如何設置切點、建立切面、加強的內容是什麼...
具體的切點表達式使用仍是前往:Spring【AOP模塊】就這麼簡單看吧~~
對應的加強註解:
其實前置啊、後置啊這些很容易就理解了,整篇文章看下來就只有這個引介/引入切面有點搞頭。因而咱們就來玩玩吧~
咱們來看一下具體的用法吧,如今我有個服務員的接口:
public interface Waiter { // 向客人打招呼 void greetTo(String clientName); // 服務 void serveTo(String clientName); }
一位年輕服務員實現類:
public class NaiveWaiter implements Waiter { public void greetTo(String clientName) { System.out.println("NaiveWaiter:greet to " + clientName + "..."); } @NeedTest public void serveTo(String clientName) { System.out.println("NaiveWaiter:serving " + clientName + "..."); } }
如今我想作的就是:想這個服務員能夠充當售貨員的角色,能夠賣東西!固然了,我確定不會加一個賣東西的方法到Waiter接口上啦,由於這個是暫時的~
因此,我搞了一個售貨員接口:
public interface Seller { // 賣東西 int sell(String goods, String clientName); }
一個售貨員實現類:
public class SmartSeller implements Seller { // 賣東西 public int sell(String goods,String clientName) { System.out.println("SmartSeller: sell "+goods +" to "+clientName+"..."); return 100; } }
此時,咱們的類圖是這樣子的:
如今我想幹的就是:藉助AOP的引入/引介切面,來讓咱們的服務員也能夠賣東西!
咱們的引入/引介切面具體是這樣乾的:
@Aspect public class EnableSellerAspect { @DeclareParents(value = "com.smart.NaiveWaiter", // 指定服務員具體的實現 defaultImpl = SmartSeller.class) // 售貨員具體的實現 public Seller seller; // 要實現的目標接口 }
寫了這個切面類會發生什麼??
是否是很神奇??我也以爲很神奇啊,咱們來測試一下:
咱們的bean.xml
文件很簡單:
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"> <aop:aspectj-autoproxy/> <bean id="waiter" class="com.smart.NaiveWaiter"/> <bean class="com.smart.aspectj.basic.EnableSellerAspect"/> </beans>
測試一下:
public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/smart/aspectj/basic/beans.xml"); Waiter waiter = (Waiter) ctx.getBean("waiter"); // 調用服務員原有的方法 waiter.greetTo("Java3y"); waiter.serveTo("Java3y"); // 經過引介/引入切面已經將waiter服務員實現了Seller接口,因此能夠強制轉換 Seller seller = (Seller) waiter; seller.sell("水軍", "Java3y"); } }
具體的調用過程是這樣子的:
當引入接口方法被調用時,代理對象會把此調用委託給實現了新接口的某個其餘對象。實際上,一個Bean的實現被拆分到多個類中
咱們知道註解很方便,可是,要想使用註解的方式使用Spring AOP就必需要有源碼(由於咱們要在切面類上添加註解)。若是沒有源碼的話,咱們就得使用XML來聲明切面了~
其實就跟註解差很少的功能:
咱們就直接來個例子終結掉它吧:
首先咱們來測試一下與傳統的SpringAOP結合的advisor是怎麼用的:
實現類:
xml配置文件:
.......
一個一個來說解仍是太花時間了,我就一次性用圖的方式來說啦:
最後還有一個切面類型總結圖,看完就幾乎懂啦:
看起來AOP有不少不少的知識點,其實咱們只要記住AOP的核心概念就行啦。
下面是個人簡要總結AOP:
最後,將咱們上一次IOC的思惟導圖補充AOP的知識點上去吧~~~
參考資料:
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠 關注微信公衆號:Java3y。爲了你們方便,剛新建了一下 qq羣:742919422,你們也能夠去交流交流。謝謝支持了!但願能多介紹給其餘有須要的朋友
文章的目錄導航: