AOP的基本概念理解

本文部分引用了網絡資源,僅爲學習,如有冒犯,請見諒。

1.1  相關概念

1、AOP技術起源(轉)

AOP技術的誕生並不算晚,早在1990年開始,來自Xerox Palo Alto Research Lab(即PARC)的研究人員就對面向對象思想的侷限性進行了分析。他們研究出了一種新的編程思想,藉助這一思想或許可以通過減少代碼重複模塊從而幫助開發人員提高工作效率。隨着研究的逐漸深入,AOP也逐漸發展成一套完整的程序設計思想,各種應用AOP的技術也應運而生。

AOP技術在Java平臺下是最先得到應用的。就在PARC對於面向方面編程進行研究的同時,美國Northeastern University的博士生Cristina Lopes和其同事也開始了類似的思考。最終,美國國防先進技術研究計劃署(Defense Advanced Research Projects Agency即DARPA)注意到了這項工作,並提供了科研經費,鼓勵將二者的工作成果結合起來。他們通過定義一套Java語言的擴展系統,使開發者可以方便的進行面向方面的開發,這套擴展系統被稱爲AspectJ。之後,AspectJ在2002年被轉讓給Eclipse Foundation,從而成爲在開源社區中AOP技術的先鋒,也是目前最爲流行的AOP工具。

AspectWerkz則是基於Java的動態的、輕量級AOP框架。AspectWerkz仍然是開源社區中的產品,由BEA System提供贊助,開發者則是BEA的兩名員工Jonas Bonér和Alexandre Vasseur。最近版本是AspectWerkz 2.0。2005年1月,AspectJ和AspectWerkz達成協議,同意將二者的成果綜合到一起,取其精華創建一個單一的工具。他們合作的第一個發佈版本爲AspectJ 5,它擴展了AspectJ語言,以支持基於Annotation開發風格而又支持類似AspectJ代碼風格。AspectJ 5也爲Java 5的語言特性提供完全的AOP支持。

在Java陣營中,商用軟件製造商JBoss在其2004年推出的JBoss 4.0中,引入了AOP框架和組件。在JBoss 4.0中,用戶可以在JBoss應用服務器外部單獨使用JBoss AOP,該版本爲JBoss AOP 1.0,是在2004年10月發佈的。在2005年,JBoss AOP框架又發佈了1.3.0版本,新版本對加載期織入(Weev)和切點(point cut)匹配的性能做了很大的優化,使應用程序的啓動時間大大縮短。

作爲輕型的Framework,Spring在開發輕量級的J2EE時,應用是非常廣泛的。它通過IoC模式(Inversion of Control,控制反轉模式)來實現AOP,通常被稱爲Spring AOP。在2004年,被作爲Spring框架的擴展而發佈。Spring AOP作爲一種非侵略性的,輕型的AOP框架,開發者無需使用預編譯器或其他的元標籤,在Java程序中應用AOP。目前,AOP的功能完全集成到了Spring事務管理、日誌和其他各種特性的上下文中。

在.Net的陣營中,AOP技術的應用遠不如Java陣營對AOP的關注。2005年1月,微軟發佈的Enterprise Library提供了7種不同的“應用程序塊(application blocks)”。有個別專家認爲,這些組件可以被認爲是方面。但該觀點並未得到一致的認同。事實上,在.Net平臺下,推動AOP技術發展的原動力並非微軟,而是開源社區。雖然,微軟的技術專家們亦然聽到了在.Net Framework中增加AOP技術的羣衆呼聲,但作爲如此巨大的軟件公司,要讓它靈活地轉變戰略方向,顯然是不太現實的。正因爲此,才賜予了開源社區在AOP技術的研究與探索上一個巨大的發展空間。

與Java陣營中的AOP技術不同,目前在.Net平臺下的各種AOP工具,基本上還停留在實驗室階段。但一些在技術上領先且逐漸成熟的AOP產品,也在開源社區中漸露崢嶸。這其中主要包括Aspect#,AspectDNG,Eos AOP等。

Aspect#是基於Castle動態代理技術來實現的。Castle源於Apache Avalon項目,其目的在於實現一個輕量級的IoC容器。Aspect#於2005年6月被收錄爲Castle的其中一個子項目。它是針對CLI(.Net和Mono)實現的AOP框架,利用了反射、代理等機制。目前的Aspect#版本爲2.1.1。

AspectDNG目前的版本爲0.7,仍然處於beta版的階段。它的實現技術是基於rail的靜態織入。Rail屬於IL級別下的代碼織入,它自定義的一套xml格式的ILML語言,能夠將原有的程序集拆散成ILML格式,以便於對靜態程序集進行修改和擴展,從而達到靜態織入的目的。因爲AspectDNG是屬於IL級別下的代碼織入,因此在.Net平臺下,並不受具體的編程語言限制。

Eos AOP與AspectDNG一樣,仍然採用靜態織入的方式,但從語法定義上,它更近似於AspectJ關於AOP的實現。它擴展了C#語法,引入了aspect、introduce、before、after等關鍵字,並且提供了專用的Eos編譯器。Eos項目是於2004年9月開始啓動,2005年6月推出的0.3.3版本爲最新版本,主要的開發人員爲Hridesh Rajan和Kevin Sullivan。前者爲Virginia大學計算機系的研究生,Eos項目最初是由Hridesh Rajan提出的;而後者則爲該計算機系的副教授(Associate Professor)。所以自Eos誕生之初,就帶有濃厚的學院派特色。

從AOP技術的整體發展來看,高性能、穩定、可擴展、易用的AOP框架是其趨勢與目標。從上述對各種AOP技術的分析來看,AOP技術無疑是具有共同特點的,而各種實現技術就是圍繞着這些共性深入與延伸。接下來,我將概要地介紹AOP的本質,以及它的技術要素。

2、  AOP

AOP是設計思想,一個規範,本身並沒有設定具體語言的實現,是對oop的一個擴展。簡單地說,AOP就是將那些與業務無關,卻爲業務模塊所共同需要的功能(或者邏輯,比如權限認證、日誌、事務處理)封裝起來,便於減少系統的重複代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。從業務上說,AOP的核心思想就是“將應用程序中的商業邏輯同對其提供支持的通用服務進行分離。

3、  AOP能做哪些事情

l  性能監控:在方法調用前後記錄調用時間,方法執行太長或超時報警。

l  緩存代理:緩存某方法的返回值,下次執行該方法時,直接從緩存裏獲取。

l  軟件破解:使用AOP修改軟件的驗證類的判斷邏輯。

l  工作流系統:工作流系統需要將業務代碼和流程引擎代碼混合在一起執行,可以使用AOP將其分離,並動態掛接業務。

l  權限驗證:方法執行前驗證是否有權限執行當前方法。

l  事物管理

1.2  實現方法(與spring無關)

1.2.1  靜態aop(靜態織入,靜態代理)

原理:在編譯期,切面直接以字節碼形式編譯到目標字節碼文件中。也就是說,aop的處理邏輯直接體現在編譯後的class文件中。這種實現方式有靜態代理方式、aspectj

優點:對系統性能無影響; 

缺點:不夠靈活;

靜態代理方式的代碼示例:

1、  定義接口:

/**

 * 抽象主題角色:聲明瞭真實主題和代理主題的共同接口。

 *

 * @author yanbin

 *

 */

public interface ITalk {

 

    public void talk(String msg);

 

}

2、  定義真實的實現類:

/**

 * 真實主題角色:定義真實的對象。

 *

 * @author yanbin

 *

 */

public class PeopleTalkimplementsITalk {

 

    public String username;

    public String age;

 

    public PeopleTalk(String username, String age) {

       this.username = username;

       this.age = age;

    }

 

    public void talk(String msg) {

       System.out.println(msg + "!你好,我是" + username + ",我年齡是" + age);

    }

 

    public String getName() {

       return username;

    }

 

    public void setName(String name) {

       this.username = name;

    }

 

    public String getAge() {

       return age;

    }

 

    public void setAge(String age) {

       this.age = age;

    }

 

}

3、  定義代理類:

/**

 * 代理主題角色:內部包含對真實主題的引用,並且提供和真實主題角色相同的接口。

 *

 * @authoryanbin

 *

 */

public class TalkProxy implements ITalk {

 

    private ITalk talker;

 

    publicTalkProxy(ITalk talker) {

        //super();

       this.talker = talker;

    }

 

    public voidtalk(String msg) {

        //dosome other job like loging

        talker.talk(msg);

      //do some other job

    }

 

}

4、  測試類:

/**

 * 代理測試類,使用代理

 *

 * @authoryanbin

 *

 */

public class ProxyPattern {

 

    publicstatic void main(String[] args) {

        // 不需要執行額外方法的。

        ITalkpeople = new PeopleTalk("AOP", "18");

       people.talk("No ProXY Test");

       System.out.println("-----------------------------");

        // 需要執行額外方法的(切面)

       TalkProxy talker = new TalkProxy(people);//使用代理類代理原始類來使用

       talker.talk("ProXY Test", "代理");

    }

 

}

1.2.2  動態aop(包括動態代理、動態字節碼生成、自定義類加載器、字節碼轉換)

1.2.2.1  動態代理 (java動態代理)

原理:在運行期,目標類加載後,爲接口動態生成代理類。將切面織入到代理類中。java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。只能對實現了接口的類進行代理。

優點:更靈活;

缺點:切入的關注點要實現接口(即目標類要基於接口實現)

實現方式參見1.5 動態代理。

1.2.2.2  動態字節碼生成(cglib)

原理:在運行期,目標類加載後,動態構建字節碼文件生成目標類的子類,將切面邏輯加入到子類中。

cglib(CodeGeneration Library)是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。cglib封裝了asm,可以在運行期動態生成新的class。cglib用於AOP,jdk中的proxy必須基於接口,cglib卻沒有這個限制。

優點:沒有接口也可以織入;

缺點:擴展類的實例方法爲final時,無法進行織入; 

示例代碼:

1、創建業務類:

public class People {
public void talk(String msg) {
       System.out.println("people talk" + msg);
   }
}

2、創建cglib代理類:

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;


public class CglibProxy implements MethodInterceptor {
    private Object target;
    /**
     * 創建代理對象
     * 
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        // 回調方法
        enhancer.setCallback(this);
        // 創建代理對象
        return enhancer.create();
    }


    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object result = null;
        System.out.println("方法開始執行");
        result = methodProxy.invokeSuper(proxy, args);
        System.out.println("事方法執行解鎖");
        return result;
    }

}

3、測試類:

public class Test {
public static void main(String[] args){

People people = (People) new CglibProxy().getInstance(new People());
       people.talk("業務方法");
}
}

執行結果如下:

事物開始
people talk業務方法
事物結束

1.2.2.3  自定義類加載器

原理:在運行期,目標加載前,將切面邏輯加到目標字節碼裏;

優點:可以對絕大部分類進行織入;

缺點:代碼中若使用了其它類加載器,則這些類將不會被織入; 

1.2.2.4  字節碼轉換

原理:在運行期,所有類加載器加載字節碼前進行攔截;

優點:可以對所有類進行織入;

缺點:
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章