• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    AOP和AspectJ

    發布: 2007-6-07 16:38 | 作者: 網絡轉載 | 來源: 網絡 | 查看: 44次 | 進入軟件測試論壇討論

    領測軟件測試網

    需求和問題

    以上篇《AOP是什么》中并發訪問應用為例子:

    多個訪問類同時訪問一個共享數據對象時,每個訪問類在訪問這個數據對象時,需要將數據對象上鎖,訪問完成后,再實行解鎖,供其它并發線程訪問,這是我們處理并發訪問資源的方式。

    為了實現這個需求,先實現傳統的編程,這里我們假定有一個寫鎖,對數據對象實行寫之前,首先對這個對象進行上寫鎖,寫操作完畢后,必須釋放寫鎖。

    首先,我們需要一個鎖,這個鎖可以是數據對象中一個字段或其它,這里使用Doug Lea的ReentrantWriterPreferenceReadWriteLock作為我們的鎖資源。

    import EDU.oswego.cs.dl.util.concurrent.*;

    public class Worker extends Thread {

      Data data;

      ReentrantWriterPreferenceReadWriteLock rwl = 
        new ReentrantWriterPreferenceReadWriteLock();

      public boolean createData() {
       try {
        rwl.writeLock().acquire(); //上鎖

        //對data實行寫邏輯操作 
           
       }catch() {
         return false;
       }finally{
         rwl.writeLock().release();  //解鎖
       }
       return true;
      }

      public boolean updateData() {
       try {
        rwl.writeLock().acquire();//上鎖

        //對data實行寫邏輯操作 
           
       }catch() {
         return false;
       }finally{
         rwl.writeLock().release(); //解鎖
       }
       return true;
      }

      public void run() {
        //執行createData()或updateData()
      }
    }

    假設可能存在另外一個訪問類,也將對數據對象實現寫操作,代碼如下:

    import EDU.oswego.cs.dl.util.concurrent.*;

    public class AnotherWorker extends Thread {

      Data data;

      ReentrantWriterPreferenceReadWriteLock rwl = 
        new ReentrantWriterPreferenceReadWriteLock();
      
      public boolean updateData() {
       try {
        rwl.writeLock().acquire();//上鎖

        //對data實行寫邏輯操作 
           
       }catch() {
         return false;
       }finally{
         rwl.writeLock().release(); //解鎖
       }
       return true;
      }

      public void run() {
        //執行updateData()
      }
    }

    以上是Java傳統編程的實現,這種鎖的實現方式是在每個具體類中實現,如下圖:

    這種實現方式的缺點很多:

    冗余:有很多重復的編碼,如rwl.writeLock().acquire()等;
    減少重用:worker的updateData()方法重用性幾乎為零。
    "數據對象寫操作必須使用鎖控制這個設計目的"不容易顯現,如果更換了一個新的程序員,他可能編寫一段不使用鎖機制就對這個數據對象寫操作的代碼。

    如果上述代碼有讀功能,那么我們需要在代碼中實現先上讀鎖,當需要寫時,解讀鎖,再上寫鎖等等,如果稍微不小心,上鎖解鎖次序搞錯,系統就隱含大的BUG,這種可能性會隨著這個數據對象永遠存在下去,系統設計大大的隱患!

    那么我們使用AOP概念來重新實現上述需求,AOP并沒有什么新花招,只是提供了觀察問題的一個新視角度。

    這里我們可以拋開新技術迷人霧障,真正核心還是新思維、新視點,人類很多問題如果換一個腦筋看待理解,也許結果真的是翻天覆地不一樣啊,所以,作為人自身,首先要重視和你世界觀和思維方式不一樣的人進行交流和溝通。

    現實生活中有很多"不公平",例如某個小學畢業生成了千萬富翁,你就懷疑知識無用,也許你認為他的機會好,其實你可能不知道,他的觀察問題的視角比你獨特,或者他可能會經常換不同的角度來看待問題和解決問題,而你由于過分陷入一個視角的具體實現細節中,迷失了真正的方向,要不說是讀書人腦子僵化呢?

    言歸正傳,我們看看AOP是如何從一個新的視角解決上述問題的。

    如果說上面代碼在每個類中實現上鎖或解鎖,類似橫向解決方式,那么AOP是從縱向方面來解決上述問題,縱向解決之道示意圖如下:

    AOP把這個縱向切面cross-cuts稱為Aspect(方面),其實我認為AOP翻譯成面向切面編程比較好,不知哪個糊涂者因為先行一步,翻譯成“面向方面編程”如此抽象,故弄玄虛。

    AspectJ實現

    下面我們使用AOP的實現之一AspectJ來對上述需求改寫。AspectJ是AOP最早成熟的Java實現,它稍微擴展了一下Java語言,增加了一些Keyword等,pointcut的語法如下:

    public pointcut 方法名:call(XXXX)

    AspectJ增加了pointcut, call是pointcut類型,有關AspectJ更多基本語法見這里。因為AspectJ使用了一些特別語法,所以Java編譯器就不能用SUN公司提供javac了,必須使用其專門的編譯器,也許SUN在以后JDK版本中會引入AOP。

    使用AspectJ如何實現上圖所謂切面式的編程呢?首先,我們將上圖縱向切面稱為Aspect,那么我們建立一個類似Class的Aspect,Java中建立一個Class代碼如下:

    public class MyClass{
      //屬性和方法 ...
    }

    同樣,建立一個Aspect的代碼如下:

    public aspect MyAspect{
      //屬性和方法 ...
    }

    建立一個Aspect名為Lock,代碼如下:

    import EDU.oswego.cs.dl.util.concurrent.*;

    public aspect Lock {

      ......
      ReentrantWriterPreferenceReadWriteLock rwl = 
        new ReentrantWriterPreferenceReadWriteLock();

      public pointcut writeOperations():
        execution(public boolean Worker.createData()) ||
        execution(public boolean Worker.updateData()) ||
        execution(public boolean AnotherWorker.updateData()) ;


      before() : writeOperations() {
        rwl.writeLock().acquire();//上鎖 advice body
      }

      after() : writeOperations() {
         rwl.writeLock().release(); //解鎖 advice body
      }

      ......
    }

    上述代碼關鍵點是pointcut,意味切入點或觸發點,那么在那些條件下該點會觸發呢?是后面紅字標識的一些情況,在執行Worker的createData()方法,Worker的update方法等時觸發。

    before代表觸發之前做什么事情?

    答案是上鎖。

    after代表觸發之后做什么事情?

    答案是上鎖。

    通過引入上述aspect,那么Worker代碼可以清潔如下:

    public class Worker extends Thread {

    Data data;

    public boolean createData() {
       try {
        //對data實行寫邏輯操作        
       }catch() {
         return false;
       }
       return true;
      }

    public boolean updateData() {
       try {
        //對data實行寫邏輯操作        
       }catch() {
         return false;
       }finally{
       }
       return true;
      }

    public void run() {
        //執行createData()或updateData()
      }
    }

    Worker中關于“鎖”的代碼都不見了,純粹變成了數據操作的主要方法。

    AOP術語

    通過上例已經知道AspectJ如何從切面crosscutting來解決并發訪問應用需求的,其中最重要的是引入了一套類似事件觸發機制。

    Pointcut類似觸發器,是事件Event發生源,一旦pointcut被觸發,將會產生相應的動作Action,這部分Action稱為Advice。

    Advice在AspectJ有三種:before、 after、Around之分,上述aspect Lock代碼中使用了Advice的兩種before和after。

    所以AOP有兩個基本的術語:Pointcut和Advice。你可以用事件機制的Event和Action來類比理解它們。上述并發訪問應用中pointcut和advice如下圖所示:

    小結如下:
    advice - 真正的執行代碼,或者說關注的實現。 類似Action。
    join point - 代碼中激活advice被執行的觸發點。
    pointcut - 一系列的join point稱為pointcut,pointcut有時代指join point

    其中advice部分又有:
    Interceptor - 解釋器并沒有在AspectJ出現,在使用JDK動態代理API實現的AOP框架中使用,解釋有方法調用或對象構造或者字段訪問等事件,是調用者和被調用者之間的紐帶,綜合了Decorator/代理模式甚至職責鏈等模式。

    Introduction - 修改一個類,以增加字段、方法或構造或者執行新的接口,包括Mixin實現。

    例如上述并發訪問應用中,如果想為每個Data對象生成相應的aspect Lock,那么可以在aspect Lock中人為數據對象增加一個字段lock,如下:

    aspect Lock {

      Data sharedDataInstance;
      Lock( Data d ) {
         sharedDataInstance = d;
      }

      introduce Lock Data.lock; //修改Data類,增加一字段lock

      advise Data() { //Data構造時觸發
         static after {
           //當Data對象生成時,將Data中lock字段賦值為aspect Lock
           //為每個Data對象生成相應的aspect Lock
           thisObject.lock = new Lock( thisObject );
         }
       }
      ....

    }

    上述代碼等于在Data類中加入一行:

    public class Data{
      ......
      Lock lock = new Lock();
      ......
    }

    還有其它兩個涉及AOP代碼運行方式:

    weaving - 將aspect代碼插入到相應代碼中的過程,一般是編譯完成或在運行時動態完成。取決于具體AOP產品,例如AspectJ是使用特殊編譯器在編譯完成weaving,而nanning、JBoss AOP是使用動態代理API,因此在運行時動態完成weaving的。
    instrumentor - 用來實現weaving功能的工具。

    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/

    TAG: aop aspectj


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備2023014753號-2
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>