1. 程式人生 > >Spring學習日記三------AOP原理篇

Spring學習日記三------AOP原理篇

AOP概論

        AOP(Aspect-Oriented Programming,面向切面的程式設計),談起AOP,則一定會追溯到OOP(Object Oriented Programming,面向物件程式設計),因為AOP可以說是對OOP的補充和完善,而這一切的理念都是從模組化開始的。OOP是一種非常成功、極具表現力的程式設計正規化,它將概念自然地表達為物件,從而將其中通用的程式碼模組化。所以,衡量OOP成功與否的標準就是它在多大程度上避免了程式碼的重複。一般情況下,OOP能夠很好地避免程式碼重複。具體繼承可以幫助我們在不同型別之間共享相同的行為;多型讓我們可以用同樣的方式來處理不同型別之間的物件,能夠讓我們將注意力集中在他們的共同之處。但當遇上一些特定問題的時候,比如,當我們需要為分散的物件引入公共行為時,OOP就顯得很無力了。也就是說,OOP很適合你定義從上到下的關係,但不適合定義水平的關係。可以說因為有這些Bug的存在,是AOP生成的直接誘因,所以是為了彌補OOP而存在的。AOP在看待應用程式結構的方式上與OOP是截然不同的,以AOP的思路來看,系統是被分解成方面(Aspect)或者關注點(Concern),而不是一個個物件。追根溯源,

與OOP一樣,AOP只不過是一種全新的模組化機制而已,他的主要作用是用來描述分散在物件、類或函式中的橫切關注點,從關注點中分離出橫切關注點則是 AOP的核心概念。

        AOP的原理,也是非常簡單的,即通過分離關注點讓解決特定領域問題的程式碼從業務邏輯中獨立出來,業務邏輯的程式碼中就不再含有針對特定領域問題程式碼的呼叫,業務邏輯同特定領域問題的關係則通過切面來封裝、維護,這樣原本分散在整個應用程式中的程式碼就可以很好的進行管理了。例如:在使用公共函式的時候,往往需要進行一些邏輯設計,也就時需要程式碼實現來支援,而這些邏輯程式碼也是需要維護的,在傳統的公共子模組的呼叫中,除了直接呼叫以外就沒有其他的手段。而相同的情況,在使用AOP後,不僅可以將這些重複的程式碼抽出來單獨維護,而且可以在需要時進行統一排程,這樣的使用方法雖然與設計公共子模組有幾分相似,但他為這一類問題的解決提供了一整套完整的理論和靈活多樣的實現方法。也就是說,在AOP提出橫切概念以後,再把模組功能正交化的同時,也在此基礎上提供了一系列橫切的靈活實現。

AOP體系

       實現原理

         在編譯期修改原始碼、執行期節碼加載前修改位元組碼或位元組碼載入後動態建立代理類的節碼,這是AOP的具體實現方法,而他是由三個重要步驟來完成的,先是生成代理物件,然後是攔截器的作用,最後是編織的具體實現。AOP框架的豐富,其實很大程度上體現在這三個步驟上所具有的豐富技術選擇,以及與IOC容器之間的無縫縫合。而如果以實現方法來分的話,則主要有兩類:靜態AOP(包括靜態織入)和動態AOP(包含動態代理、動態節碼生成、自定義類載入器、節碼轉換器)。

       結構概述

        除了通過使用Proxy代理物件、攔截器位元組碼翻譯技術等一系列已有的AOP或者AOP實現技術,來實現切面應用的各種編織實現和環繞增強以外。還成立了AOP聯盟來探索AOP的標準化,希望藉此來推動AOP的發展。而對於現在已有的AOP實現方案,AOP聯盟對它們進行了一定程度的抽象,從而定義出了AOP的體系結構。結合這個AOP體系結構去了解AOP技術是非常有幫助的,AOP聯盟定義的AOP體系結構如圖所示:

        AOP聯盟定義的AOP體系結構把與AOP相關的概念大致分為由高到低、從使用到實現的三個層次。從上往下:

        最高層是語言和開發環境,在這個環境中可以看到幾個重要的概念:“基礎”可以視為待增強物件或者說目標物件;“切面”通常包含對於基礎的增強應用;“配置”可以看成是一種編織,通過在AOP體系中提供這個配置環境,可以把基礎和切面結合起來,從而完成切面對目標物件的編織實現。

        AOP體系結構的第二層次為語言和開發環境提供支援的,在這個層次中可以看到AOP框架的高層實現,主要包括配置和編織實現兩部分內容。例如配置邏輯和編織邏輯實現本身,以及對這些實現進行抽象的一些高層API封裝。這些實現和API封裝,為前面提到的語言和開發環境的實現提供了有力的支援。

        最底層是編織的具體實現模組,各種技術都可以作為編織邏輯的具體實現方法,比如反射、程式預處理、攔截器框架、類裝載器框架、元資料處理等等。

       使用概況

        AOP在 許可權(Authentication)、快取(Cache)、內容傳遞(Context passing)、錯誤處理(Error handling)、懶載入(Lazy loading)、除錯(Debug)、日誌(Log)、跟蹤優化和校準(tracing、profiling and monitoring)、效能優化(Performance optimization)、持久化(Persistence)、資源池(Resource pooling)、同步(Synchronization)、事務(Transactions)等方面都有用處,可以說是可使用範圍及廣。下面我們就以一張思維導圖來串聯,以此來鋪開與AOP相關的所有的知識點。

                AOP通常包含以下相關術語:

                        1、目標物件(Target):包含連線點的物件。也被用來引用增強化或代理化物件。

                        2、代理(Proxy):AOP 框架建立的物件,包含增強。

                        3、連線點(Joinpoint):程式執行過程中明確的點,如方法的呼叫或特定的異常被丟擲。

                        4、切點(Pointcut):指定一個通知將被引發的一系列連線點。AOP 框架必須允許開發者指定切入點:例如,使用正則表示式。

                        5、增強(Advice):在特定的連線點AOP框架執行的動作。各種型別的增強包括“around”、“before”、“throws”增強等等。增強型別將在下面討論。許多 AOP 框架都是以攔截器做增強模型,維護一個“圍繞”連線點的攔截器鏈。

                        6、切面(Advisor):一個關注點的模組化,這個關注點實現可能另外橫切多個物件。事物管理是J2EE應用中橫切關注點中一個很好的例子。切面一般是用 Advisor 或者 攔截器實現。

                        7、織入(Weaving):組裝方面建立通知化物件。這可以在編譯時完成(例如:使用AspectJ編譯器),也可以在執行時完成。Spring 和其他一些純 Java AOP 框架,使用執行時織入。

                        8、引入(Introduction):新增方法或欄位到增強化類。

           9、介面(IsModified):用於簡化快取。(這裡作為補充)。

                AOP增強型別(也叫 通知型別)包括:

                        1、Before Advice(前置增強):在一個連線點之前執行的增強,但這個增強不能阻止流程繼續執行到連線點(除非它丟擲一個異常)。

                        2、After Advice(後置增強,全稱是 After returning advice 正常返回增強 ):在連線點正常完成後執行的增強,例如,如果一個正常返回,沒有丟擲異常。如果丟擲異常則不會執行。

                        3、Around Advice(環繞增強):包圍一個連線點的增強,如方法呼叫,是最強大的增強。在方法呼叫前後完成自定義的行為。它們負責選擇繼續執行連線點或直接返回它們自己的返回值或丟擲異常來執行。

                        4、Throws Advice(丟擲增強,全稱是 After throwing advice 異常返回增強,也叫 Finally returning advice 最終返回增強):是最常用的增強型別。大部分是基於攔截器框架如Nanning或者JBoss4提供的Around增強。作用是,不管,是否正常執行,都會返回增強中的內容。

                        5、Introduction Advice(引入增強):一種非常特殊的增強。它將新的成員變數、成員方法引入到目標類中。它僅能作用於類層次,而不是方法層次,所以他不能作用於任何切入點。

Spring AOP 實現原理

        AOP模組是Spring的核心模組,儘管Spring中有自己的一套AOP實現,但在Java社群中是最完整AOP框架還是Aspectj,所以為了彌補自己的不足,也為了提供更加豐富的AOP解決方案,Spring對Aspectj做了整合。同時,再配合Spring的IOC容器,Spring推出了一個完善的AOP解決方法。

        Spring AOP的核心技術是JDK的動態代理技術。Spring AOP是以動態代理技術為基礎,設計出了一系列AOP的橫切實現,比如:前置增強、返回增強、異常增強等等。同時,Spring AOP還提供了一系列的Pointcut來匹配切入點,可以使用現有的切入點來設計橫切面,也可以擴充套件相關的Pointcut方法來切入需求。

        在Spring AOP 中,我們一般是通過配置檔案或者程式設計的方式來實現的。常見的配置方法有四種:1,配置 ProxyFactoryBean 顯示設定 advisors、advice、target 等。2,配置 AutoProxyCreator 這種方式下,還是如以前一樣定義 bean,但是從容器中獲得的其實是代理物件。3,配置 <aop:config>。4,配置 <aop:aspectj-autoproxy>,使用 AspectJ 的註解來表示之前以及切入點。而程式設計方式是直接通過 ProxyFactory 設定 target 物件,再通過 getProxy 方法來獲取代理物件。 

         總的來說,在Spring AOP中,對於AOP的使用者來說,可能簡單配置 Bean 即可,但仔細分析 Spring AOP 的內部設計就可以看到,為了讓AOP起作用,需要參照前面的 AOP 實現原理來完成一系列過程,需要為目標物件建立代理物件,這個代理物件可以通過使用JDK的Proxy來完成,也可以通過第三方的類生成器CGLIB來完成。然後,還需要啟動代理物件的攔截器來完成各種橫切面的織入,這一系列的織入設計時通過一系列 Adapter 來實現的。通過一系列 Adapter 的設計,就可以把AOP的橫切面設計和Proxy模式有機地結合起來,從而實現在 AOP 中定義各種織入方式(這裡的原始碼部分可能不會涉及)。具體實現過程筆者會在後面的文章中詳細闡述。