AOP的概念和使用原因
現實中有一些內容並不是面向對象(OOP)可以解決的,比如數據庫事務,它對於企業級的Java EE應用而言是十分重要的,又如在電商網站購物需要經過交易系統、財務系統,對於交易系統存在一個交易記錄的對象,而財務系統則存在賬戶的信息對象。從這個角度而言,我們需要對交易記錄和賬戶操作形成一個統一的事務管理。交易和賬戶的事務,要么全部成功,要么全部失敗。交易記錄和賬戶記錄都是對象,這兩個對象需要在同一個事務中控制,這就不是面向對象可以解決的問題,而需要用到面向切面的編程,這里的切面環境就是數據庫事務。
AOP編程有着重要的意義,首先它可以攔截一些方法,然后把各個對象組織成一個整體,比如網站的交易記錄需要記錄日志,如果我們約定好了動態的流程,那么就可以在交易前后、交易正常完成后或者交易異常發生時,通過這些約定記錄相關的日志了。
回到JDBC的代碼中,令人最討厭和最折騰的問題永遠是無窮無盡的try...catch...finally...語句和數據庫資源的關閉問題,而且這些代碼會存在大量重復,加上開發者水平參差不齊。Spring出現前,在Java EE的開發中,try...catch...finally語句常常被嚴重濫用,使得Java EE的開發存在着許多問題,雖然MyBatis對JDBC做了良好的封裝,但是還是不足的。

這里購買交易的產品和購買記錄都在try...catch...finally...語句中,首先需要自己去獲取對應的映射器,而業務流程中穿插着事務的提交和回滾,也就是如果交易可以成功,那么就會提交事務,交易如果發生異常,那么就回滾事務,最后在finally語句中會關閉SqlSession所持有的功能。
但是這並不是一個很好的設計,按照Spring的AOP設計思維,它希望寫成如代碼清單所示的代碼。


這段代碼除了一個注解@Transactional,沒有任何關於打開或者關閉數據庫資源的代碼,更沒有任何提交或者回滾數據庫事務的代碼,但是它卻能夠完成如代碼清單所示的全部功能。注意,這段代碼更簡潔,也更容易維護,主要都集中在業務處理上,而不是數據庫事務和資源管控上,這就是AOP的魅力。
面向切面編程的術語
1. 切面(Aspect)切面就是在一個怎么樣的環境中工作。比如數據庫的事務直接貫穿了整個代碼層面,這就是一個切面,它能夠在被代理對象的方法之前、之后,產生異常或者正常返回后切入你的代碼,甚至代替原來被代理對象的方法,在動態代理中可以把它理解成一個攔截器。
2. 通知(Adice)
•通知是切面開啟后,切面的方法。它根據在代理對象真實方法調用前、后的順序和邏輯區分,它和約定游戲的例子里的攔截器的方法十分接近。
•前置通知(before):在動態代理反射原有對象方法或者執行環繞通知前執行的通知功能。
•后置通知(after):在動態代理反射原有對象方法或者執行環繞通知后執行的通知功能。無論是否拋出異常,它都會被執行。
•返回通知(afterReturning):在動態代理反射原有對象方法或者執行環繞通知后執行的通知功能。
•異常通知(afterThrowing):在動態代理反射原有對象方法或者執行環繞通知產生異常后執行的通知功能。
•環繞通知(aroundThrowing):在動態代理中,它可以取代當前被攔截對象的方法,通過參數或反射調用被攔截對象的方法。
3. 引入(Introduction)
引入允許我們在現有的類里添加自定義的類和方法。
4. 切點(Pointcut)
在動態代理中,被切面攔截的方法就是一個切點,切面將可以將其切點和被攔截的方法按照一定的邏輯織入到約定流程當中。
5. 連接點(join point)
連接點是一個判斷條件,由它可以指定哪些是切點。對於指定的切點,Spring會生成代理對象去使用對應的切面對其攔截,否則就不會攔截它。
6. 織入(Weaving)
織入是一個生成代理對象的過程。實際代理的方法分為靜態代理和動態代理。靜態代理是在編譯class文件時生成的代碼邏輯,但是在Spring中並不使用這樣的方式,所以我們就不展開討論了。一種是通過ClassLoader也就是在類加載的時候生成的代碼邏輯,但是它在應用程序代碼運行前就生成對應的邏輯。還有一種是運行期,動態生成代碼的方式,這是Spring AOP所采用的方式,Spring是以JDK和CGLIB動態代理來生成代理對象的
•環繞通知(aroundThrowing):在動態代理中,它可以取代當前被攔截對象的方法,通過參數或反射調用被攔截對象的方法。
3. 引入(Introduction)
引入允許我們在現有的類里添加自定義的類和方法。
4. 切點(Pointcut)
在動態代理中,被切面攔截的方法就是一個切點,切面將可以將其切點和被攔截的方法按照一定的邏輯織入到約定流程當中。
5. 連接點(join point)
連接點是一個判斷條件,由它可以指定哪些是切點。對於指定的切點,Spring會生成代理對象去使用對應的切面對其攔截,否則就不會攔截它。
6. 織入(Weaving)
織入是一個生成代理對象的過程。實際代理的方法分為靜態代理和動態代理。靜態代理是在編譯class文件時生成的代碼邏輯,但是在Spring中並不使用這樣的方式,所以我們就不展開討論了。一種是通過ClassLoader也就是在類加載的時候生成的代碼邏輯,但是它在應用程序代碼運行前就生成對應的邏輯。還有一種是運行期,動態生成代碼的方式,這是Spring AOP所采用的方式,Spring是以JDK和CGLIB動態代理來生成代理對象的

Spring對AOP的支持
AOP並不是Spring框架特有的,Spring只是支持AOP編程的框架之一。每一個框架對AOP的支持各有特點,有些AOP能夠對方法的參數進行攔截,有些AOP對方法進行攔截。而Spring AOP是一種基於方法攔截的AOP,換句話說Spring只能支持方法攔截的AOP。在Spring中有4種方式去實現AOP的攔截功能。
•使用ProxyFactoryBean和對應的接口實現AOP。
•使用XML配置AOP。
•使用@AspectJ注解驅動切面。
•使用AspectJ注入切面。
在Spring AOP的攔截方式中,真正常用的是用@AspectJ注解的方式實現的切面,有時候XML配置也有一定的輔助作用。對於ProxyFactoryBean和AspectJ注入切面的方式這兩種方式已經很少用了。
