天天看點

面向切面程式設計(AOP)初探

        面向對象程式設計通過設計和語言本身提供的子產品化、封裝、繼承、多态來實作軟體複用。盡管OOP在模組化以及實作複雜軟體方面非常成功,它仍然有一些問題。面向切面程式設計(AOP)被認為是一項有前途的新技術,它通過對交叉業務的分隔來實作,而這在面向對象程式設計裡很難做到。本文通過一個新的範例介紹AOP的基本概念。

面向對象程式設計 Object Oriented Programming

        今天,面向對象程式設計已經成為主流的程式設計模式,在這裡,現實問題被分解為一個個的包含資料和行為的對象。

在大型工程實踐中,程式員發現在子產品中越來越難以分離交叉業務,他們的代碼也變得更加難維護。對程式設計的一絲改動都會引發大量不相關子產品的改動。

交叉業務 Crosscutting Concerns

        一個交叉業務的例子是“日志”,日志在分布式系統中經常被用來記錄方法調用,以輔助調試。假設我們在每個函數開始前和結束後都寫日志,這會使我們對所有包含方法的類做“橫切”(crosscutting)。其他典型的交叉業務包括:上下文敏感的錯誤處理,性能優化,以及設計模式。

交叉業務可能出現在某些程式中,尤其是那些大型程式中。然而另一方面,對系統的重新設計可以将交叉業務轉換成對象。AOP假定交叉業務會出現在程式中,并無法從重構中被剔除出去。

面向切面程式設計 Aspect Oriented Programming

        面向切面的程式設計AOP是一項新的技術,它将交叉業務分離出來,作為獨立單元——切面——處理。切面即是交叉業務的子產品化實作,它封裝了對各個類都有影響的行為,作為新的可重用的子產品。利用AOP,我們可以用OO程式設計語言(如Java)開始項目,然後我們單獨使用切面處理交叉業務。最後,代碼和切面一起通過編織器(aspect weaver)組織成最終可執行檔案。圖1說明了"編織器"工作過程。注意,原始的代碼不需要知道切面的任何功能;隻要除去切面代碼并重新編譯,就能得到初始代碼的功能。

        AOP是一種程式設計概念,是以它并未綁定到任何特定的語言。事實上,它對所有單獨的、垂直分解式(譯注:AOP通常被認為是橫向分解)的語言(不僅是OO語言)都有幫助。AOP在不同語言都有實作(如 C++, Smalltalk, C#, C, Java).

當然,受益最大的還是Java語言。下面是一些支援Java AOP的工具:

◆AspectJ

◆AspectWerkz

◆Hyper/J

◆JAC

◆JMangler

◆MixJuice

◆PROSE

◆ArchJava

        由Xerox PARC所建立的AspectJ被認為是Java語言在AOP方面的一個擴充,是專門為面向切面的程式設計而生的。本文下面部分主要涉及AspectJ.

連接配接點,切入點,通知和引入 Join points, Pointcut, Advice, and Introduction

就如OOP的概念包含繼承、封裝、多态一樣,組成AOP的概念是連接配接點,切入點,通知和引入(Join points, Pointcut, Advice, and Introduction)。為更好的了解這些術語,我們看一下下面的例子。

        我們的Java代碼儲存在TestClass.java,假設我們想用切面做如下修改:

在對TestClass.sayHello()方法調用之前和之後,都列印一行資訊;檢查TestClass.sayAnyThing() 方法的參數,至少3個字元才能執行

下面就是AspectJ 的實作。

        Line 1 定義了一個aspect,就像我們定義Java 類。跟任何Java類一樣,aspect也可以擁有成員變量和方法,另外它還可以包含切入點(pointcuts),通知(advices)和引入(introductions).

        Lines 2和Line 3指定我們的修改在TestClass什麼地方起作用。按AspectJ術語,我們定義了2個切入點(pointcuts)。為了弄清楚切入點(pointcut)是什麼意思,我們需要先定義連接配接點(join points).

        連接配接點(join points)表示在程式執行過程中預先定義的“點”,AspectJ 中典型的連接配接點包括:方法或構造器的調用,方法或構造器的執行,字段的讀取,異常處理,以及靜态或動态的初始化。本文例子中,我們定義了2處連接配接點:對TestClass.sayHello方法的調用及對TestClass.sayAnyThing方法的調用。

        切入點(Pointcut)是符合預定義規範的連接配接點(a set of join points)的集合,這是一個語言上的構造概念。 規範可以是明确的的函數名,也可以是包含通配符的函數名。

public pointcut sayMethodCall (): call (public void

TestClass.say*() );

        上面一行,我們定義了一個切入點(pointcut),叫做 sayMethodCall,它會檢查所有對TestClass.sayHello方法的調用。另外,它同樣會檢查TestClass 類裡所有以"say"開頭,參數為空的公共方法(舉個例子:TestClass.sayBye).

切入點(Pointcuts)用來定義“通知” (advice). AspectJ 的advice用來定義在連接配接點執行之前、之中、之後的額外代碼。在我們的例子中,line 4-6 和line7-9 分别定義了對第一個切入點執行之前和之後的通知。Lines10-15定義了對第二個切入點的通知,即設定TestClass.sayAnyThing 方法執行的一個前置條件。

        切入點pointcuts和通知advice能讓你影響程式的動态執行部分,與此不同,引入(introduction)允許切面修改程式中靜态的部分。通過引入(introduction), 切面可以為類添加新的方法及變量,聲明類實作的接口,或将捕獲的異常轉為未捕獲的異常。 Introduction和一個更為實用的AOP的例子是我未來一篇文章的主題。

AspectJ 編譯器

        回到開頭,你需要從AspectJ 的官方網站上下載下傳它的最新版本并安裝它(免費的),編譯和運作我們的例子非常簡單:

ajc MyAspect.aj TestClass.java

java TestClass

值得注意的是,Java源代碼TestClass.java 沒有任何改動。你隻要使用Java編譯器重新編譯它就能得到最初的原始程式功能。

繼續閱讀