<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    鷹翔宇空

    學(xué)習(xí)和生活

    BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
      110 Posts :: 141 Stories :: 315 Comments :: 1 Trackbacks
    引自:http://www.3doing.net/forums/dispbbs.asp?boardID=11&ID=138&page=1


    發(fā)貼心情?AOP研究

    為什么要區(qū)分J2EE容器和J2EE應(yīng)用系統(tǒng)?

      我們知道,J2EE應(yīng)用系統(tǒng)只有部署在J2EE容器中才能運(yùn)行,那么為什么劃分為J2EE容器和J2EE應(yīng)用系統(tǒng)? 通過(guò)對(duì)J2EE容器運(yùn)行機(jī)制的分析(見我的電子教材“EJB實(shí)用原理”),我們可以發(fā)現(xiàn):實(shí)際上J2EE容器分離了一般應(yīng)用系統(tǒng)的一些通用功能,例如事務(wù)機(jī)制、安全機(jī)制以及對(duì)象池或線程池等性能優(yōu)化機(jī)制。

      這些功能機(jī)制是每個(gè)應(yīng)用系統(tǒng)幾乎都需要的,因此可以從具體應(yīng)用系統(tǒng)中分離出來(lái),形成一個(gè)通用的框架平臺(tái),而且,這些功能機(jī)制的設(shè)計(jì)開發(fā)有一定難度,同時(shí)運(yùn)行的穩(wěn)定性和快速性都非常重要,必須經(jīng)過(guò)長(zhǎng)時(shí)間調(diào)試和運(yùn)行經(jīng)驗(yàn)積累而成,因此,形成了專門的J2EE容器服務(wù)器產(chǎn)品,如Tomcat JBoss、Websphere、WebLogic等。

      從J2EE系統(tǒng)劃分為J2EE容器和J2EE應(yīng)用系統(tǒng)兩個(gè)方面,我們已經(jīng)看到一種分散關(guān)注的思路(separation of concerns)。

    分散關(guān)注

      將通用需求功能從不相關(guān)類之中分離出來(lái);同時(shí),能夠使得很多類共享一個(gè)行為,一旦行為發(fā)生變化,不必修改很多類,只要修改這個(gè)行為就可以。

       AOP就是這種實(shí)現(xiàn)分散關(guān)注的編程方法,它將“關(guān)注”封裝在“方面”中。

    AOP是什么?

      AOP是OOP的延續(xù),是Aspect Oriented Programming的縮寫,意思是面向方面編程。AOP實(shí)際是GoF設(shè)計(jì)模式的延續(xù),設(shè)計(jì)模式孜孜不倦追求的是調(diào)用者和被調(diào)用者之間的解耦,AOP可以說(shuō)也是這種目標(biāo)的一種實(shí)現(xiàn)。

      舉例:假設(shè)有在一個(gè)應(yīng)用系統(tǒng)中,有一個(gè)共享的數(shù)據(jù)必須被并發(fā)同時(shí)訪問(wèn),首先,將這個(gè)數(shù)據(jù)封裝在數(shù)據(jù)對(duì)象中,稱為Data Class,同時(shí),將有多個(gè)訪問(wèn)類,專門用于在同一時(shí)刻訪問(wèn)這同一個(gè)數(shù)據(jù)對(duì)象。

      為了完成上述并發(fā)訪問(wèn)同一資源的功能,需要引入鎖Lock的概念,也就是說(shuō),某個(gè)時(shí)刻,當(dāng)有一個(gè)訪問(wèn)類訪問(wèn)這個(gè)數(shù)據(jù)對(duì)象時(shí),這個(gè)數(shù)據(jù)對(duì)象必須上鎖Locked,用完后就立即解鎖unLocked,再供其它訪問(wèn)類訪問(wèn)。

      使用傳統(tǒng)的編程習(xí)慣,我們會(huì)創(chuàng)建一個(gè)抽象類,所有的訪問(wèn)類繼承這個(gè)抽象父類,如下:

    abstract class Worker{

      abstract void locked();
      abstract void accessDataObject();
      abstract void unlocked();

    }


      缺點(diǎn):


    • accessDataObject()方法需要有“鎖”狀態(tài)之類的相關(guān)代碼。


    • Java只提供了單繼承,因此具體訪問(wèn)類只能繼承這個(gè)父類,如果具體訪問(wèn)類還要繼承其它父類,比如另外一個(gè)如Worker的父類,將無(wú)法方便實(shí)現(xiàn)。


    • 重用被打折扣,具體訪問(wèn)類因?yàn)橐舶版i”狀態(tài)之類的相關(guān)代碼,只能被重用在相關(guān)有“鎖”的場(chǎng)合,重用范圍很窄。

      仔細(xì)研究這個(gè)應(yīng)用的“鎖”,它其實(shí)有下列特性:


    • “鎖”功能不是具體訪問(wèn)類的首要或主要功能,訪問(wèn)類主要功能是訪問(wèn)數(shù)據(jù)對(duì)象,例如讀取數(shù)據(jù)或更改動(dòng)作。


    • “鎖”行為其實(shí)是和具體訪問(wèn)類的主要功能可以獨(dú)立、區(qū)分開來(lái)的。


    • “鎖”功能其實(shí)是這個(gè)系統(tǒng)的一個(gè)縱向切面,涉及許多類、許多類的方法。如下圖:

      因此,一個(gè)新的程序結(jié)構(gòu)應(yīng)該是關(guān)注系統(tǒng)的縱向切面,例如這個(gè)應(yīng)用的“鎖”功能,這個(gè)新的程序結(jié)構(gòu)就是aspect(方面)

      在這個(gè)應(yīng)用中,“鎖”方面(aspect)應(yīng)該有以下職責(zé):

      提供一些必備的功能,對(duì)被訪問(wèn)對(duì)象實(shí)現(xiàn)加鎖或解鎖功能。以保證所有在修改數(shù)據(jù)對(duì)象的操作之前能夠調(diào)用lock()加鎖,在它使用完成后,調(diào)用unlock()解鎖。

    AOP應(yīng)用范圍

      很明顯,AOP非常適合開發(fā)J2EE容器服務(wù)器,目前JBoss 4.0正是使用AOP框架進(jìn)行開發(fā)。
      具體功能如下:
    Authentication 權(quán)限
    Caching 緩存
    Context passing 內(nèi)容傳遞
    Error handling 錯(cuò)誤處理
    Lazy loading 懶加載
    Debugging  調(diào)試
    logging, tracing, profiling and monitoring 記錄跟蹤 優(yōu)化 校準(zhǔn)
    Performance optimization 性能優(yōu)化
    Persistence  持久化
    Resource pooling 資源池
    Synchronization 同步
    Transactions 事務(wù)

    AOP有必要嗎?

      當(dāng)然,上述應(yīng)用范例在沒有使用AOP情況下,也得到了解決,例如JBoss 3.XXX也提供了上述應(yīng)用功能,但是沒有使用AOP。

      但是,使用AOP可以讓我們從一個(gè)更高的抽象概念來(lái)理解軟件系統(tǒng),AOP也許提供一種有價(jià)值的工具。可以這么說(shuō):因?yàn)槭褂肁OP結(jié)構(gòu),現(xiàn)在JBoss 4.0的源碼要比JBoss 3.X容易理解多了,這對(duì)于一個(gè)大型復(fù)雜系統(tǒng)來(lái)說(shuō)是非常重要的。

      從另外一個(gè)方面說(shuō),好像不是所有的人都需要關(guān)心AOP,它可能是一種架構(gòu)設(shè)計(jì)的選擇,如果選擇J2EE系統(tǒng),AOP關(guān)注的上述通用方面都已經(jīng)被J2EE容器實(shí)現(xiàn)了,J2EE應(yīng)用系統(tǒng)開發(fā)者可能需要更多地關(guān)注行業(yè)應(yīng)用方面aspect。

    AOP具體實(shí)現(xiàn)

      AOP是一個(gè)概念,并沒有設(shè)定具體語(yǔ)言的實(shí)現(xiàn),它能克服那些只有單繼承特性語(yǔ)言的缺點(diǎn)(如Java),目前AOP具體實(shí)現(xiàn)有以下幾個(gè)項(xiàng)目:

      AspectJ (TM): 創(chuàng)建于Xerox PARC. 有近十年歷史,成熟
      缺點(diǎn):過(guò)于復(fù)雜;破壞封裝;需要專門的Java編譯器。

      動(dòng)態(tài)AOP:使用JDK的動(dòng)態(tài)代理API或字節(jié)碼Bytecode處理技術(shù)。

     動(dòng)態(tài)AOP:使用JDK的動(dòng)態(tài)代理API或字節(jié)碼Bytecode處理技術(shù)。

      基于動(dòng)態(tài)代理API的具體項(xiàng)目有:
      JBoss 4.0 JBoss 4.0服務(wù)器
      nanning 這是以中國(guó)南寧命名的一個(gè)項(xiàng)目,搞不清楚為什么和中國(guó)相關(guān)?是中國(guó)人發(fā)起的?

      基于字節(jié)碼的項(xiàng)目有:
      aspectwerkz 
      spring 
    在以后其它文章中,我將繼續(xù)對(duì)AOP概念進(jìn)行分析,和大家一起學(xué)習(xí)進(jìn)步。

    發(fā)貼心情?

    AOP和AspectJ

    板橋里人http://www.jdon.com 2004/01/10

    需求和問(wèn)題

      以上篇《AOP是什么》中并發(fā)訪問(wèn)應(yīng)用為例子:

      多個(gè)訪問(wèn)類同時(shí)訪問(wèn)一個(gè)共享數(shù)據(jù)對(duì)象時(shí),每個(gè)訪問(wèn)類在訪問(wèn)這個(gè)數(shù)據(jù)對(duì)象時(shí),需要將數(shù)據(jù)對(duì)象上鎖,訪問(wèn)完成后,再實(shí)行解鎖,供其它并發(fā)線程訪問(wèn),這是我們處理并發(fā)訪問(wèn)資源的方式。

      為了實(shí)現(xiàn)這個(gè)需求,先實(shí)現(xiàn)傳統(tǒng)的編程,這里我們假定有一個(gè)寫鎖,對(duì)數(shù)據(jù)對(duì)象實(shí)行寫之前,首先對(duì)這個(gè)對(duì)象進(jìn)行上寫鎖,寫操作完畢后,必須釋放寫鎖。

      首先,我們需要一個(gè)鎖,這個(gè)鎖可以是數(shù)據(jù)對(duì)象中一個(gè)字段或其它,這里使用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(); //上鎖

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

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

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

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

    假設(shè)可能存在另外一個(gè)訪問(wèn)類,也將對(duì)數(shù)據(jù)對(duì)象實(shí)現(xiàn)寫操作,代碼如下:

    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();//上鎖

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

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

      以上是Java傳統(tǒng)編程的實(shí)現(xiàn),這種鎖的實(shí)現(xiàn)方式是在每個(gè)具體類中實(shí)現(xiàn),如下圖:

    這種實(shí)現(xiàn)方式的缺點(diǎn)很多:

    • 冗余:有很多重復(fù)的編碼,如rwl.writeLock().acquire()等;
    • 減少重用:worker的updateData()方法重用性幾乎為零。
    • "數(shù)據(jù)對(duì)象寫操作必須使用鎖控制這個(gè)設(shè)計(jì)目的"不容易顯現(xiàn),如果更換了一個(gè)新的程序員,他可能編寫一段不使用鎖機(jī)制就對(duì)這個(gè)數(shù)據(jù)對(duì)象寫操作的代碼。
    • 如果上述代碼有讀功能,那么我們需要在代碼中實(shí)現(xiàn)先上讀鎖,當(dāng)需要寫時(shí),解讀鎖,再上寫鎖等等,如果稍微不小心,上鎖解鎖次序搞錯(cuò),系統(tǒng)就隱含大的BUG,這種可能性會(huì)隨著這個(gè)數(shù)據(jù)對(duì)象永遠(yuǎn)存在下去,系統(tǒng)設(shè)計(jì)大大的隱患啊!

      那么我們使用AOP概念來(lái)重新實(shí)現(xiàn)上述需求,AOP并沒有什么新花招,只是提供了觀察問(wèn)題的一個(gè)新視角度。

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

      現(xiàn)實(shí)生活中有很多"不公平",例如某個(gè)小學(xué)畢業(yè)生成了千萬(wàn)富翁,你就懷疑知識(shí)無(wú)用,也許你認(rèn)為他的機(jī)會(huì)好,其實(shí)你可能不知道,他的觀察問(wèn)題的視角比你獨(dú)特,或者他可能會(huì)經(jīng)常換不同的角度來(lái)看待問(wèn)題和解決問(wèn)題,而你由于過(guò)分陷入一個(gè)視角的具體實(shí)現(xiàn)細(xì)節(jié)中,迷失了真正的方向,要不說(shuō)是讀書人腦子僵化呢?

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

      如果說(shuō)上面代碼在每個(gè)類中實(shí)現(xiàn)上鎖或解鎖,類似橫向解決方式,那么AOP是從縱向方面來(lái)解決上述問(wèn)題,縱向解決之道示意圖如下:

      AOP把這個(gè)縱向切面cross-cuts稱為Aspect(方面),其實(shí)我認(rèn)為AOP翻譯成面向切面編程比較好,不知哪個(gè)糊涂者因?yàn)橄刃幸徊剑g成“面向方面編程”如此抽象,故弄玄虛。

    AspectJ實(shí)現(xiàn)

      下面我們使用AOP的實(shí)現(xiàn)之一AspectJ來(lái)對(duì)上述需求改寫。AspectJ是AOP最早成熟的Java實(shí)現(xiàn),它稍微擴(kuò)展了一下Java語(yǔ)言,增加了一些Keyword等,pointcut的語(yǔ)法如下:

    public pointcut 方法名:call(XXXX)

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

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

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

      同樣,建立一個(gè)Aspect的代碼如下:

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

    建立一個(gè)Aspect名為L(zhǎng)ock,代碼如下:

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

    public aspect Lock {

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

      public pointcutwriteOperations():
        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
      }

      ......
    }

      上述代碼關(guān)鍵點(diǎn)是pointcut,意味切入點(diǎn)或觸發(fā)點(diǎn),那么在那些條件下該點(diǎn)會(huì)觸發(fā)呢?是后面紅字標(biāo)識(shí)的一些情況,在執(zhí)行Worker的createData()方法,Worker的update方法等時(shí)觸發(fā)。

      before代表觸發(fā)之前做什么事情?
      答案是上鎖。

      after代表觸發(fā)之后做什么事情?
      答案是上鎖。

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

    public class Worker extends Thread {

      Data data;

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

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

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

      Worker中關(guān)于“鎖”的代碼都不見了,純粹變成了數(shù)據(jù)操作的主要方法。

    AOP術(shù)語(yǔ)

      通過(guò)上例已經(jīng)知道AspectJ如何從切面crosscutting來(lái)解決并發(fā)訪問(wèn)應(yīng)用需求的,其中最重要的是引入了一套類似事件觸發(fā)機(jī)制。

      Pointcut類似觸發(fā)器,是事件Event發(fā)生源,一旦pointcut被觸發(fā),將會(huì)產(chǎn)生相應(yīng)的動(dòng)作Action,這部分Action稱為Advice。

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

      所以AOP有兩個(gè)基本的術(shù)語(yǔ):Pointcut和Advice。你可以用事件機(jī)制的Event和Action來(lái)類比理解它們。上述并發(fā)訪問(wèn)應(yīng)用中pointcut和advice如下圖所示:

    小結(jié)如下:
    advice - 真正的執(zhí)行代碼,或者說(shuō)關(guān)注的實(shí)現(xiàn)。 類似Action。
    join point - 代碼中激活advice被執(zhí)行的觸發(fā)點(diǎn)。
    pointcut - 一系列的join point稱為pointcut,pointcut有時(shí)代指join point

    其中advice部分又有:
    Interceptor - 解釋器并沒有在AspectJ出現(xiàn),在使用JDK動(dòng)態(tài)代理API實(shí)現(xiàn)的AOP框架中使用,解釋有方法調(diào)用或?qū)ο髽?gòu)造或者字段訪問(wèn)等事件,是調(diào)用者和被調(diào)用者之間的紐帶,綜合了Decorator/代理模式甚至職責(zé)鏈等模式。

    Introduction - 修改一個(gè)類,以增加字段、方法或構(gòu)造或者執(zhí)行新的接口,包括Mixin實(shí)現(xiàn)。

    例如上述并發(fā)訪問(wèn)應(yīng)用中,如果想為每個(gè)Data對(duì)象生成相應(yīng)的aspect Lock,那么可以在aspect Lock中人為數(shù)據(jù)對(duì)象增加一個(gè)字段lock,如下:

    aspect Lock {

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

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

      advise Data() { //Data構(gòu)造時(shí)觸發(fā)
         static after {
           //當(dāng)Data對(duì)象生成時(shí),將Data中l(wèi)ock字段賦值為aspect Lock
           //為每個(gè)Data對(duì)象生成相應(yīng)的aspect Lock
           thisObject.lock = new Lock( thisObject );
         }
       }
      ....

    }

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

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

    還有其它兩個(gè)涉及AOP代碼運(yùn)行方式:

    weaving - 將aspect代碼插入到相應(yīng)代碼中的過(guò)程,一般是編譯完成或在運(yùn)行時(shí)動(dòng)態(tài)完成。取決于具體AOP產(chǎn)品,例如AspectJ是使用特殊編譯器在編譯完成weaving,而nanning、JBoss AOP是使用動(dòng)態(tài)代理API,因此在運(yùn)行時(shí)動(dòng)態(tài)完成weaving的。
    instrumentor - 用來(lái)實(shí)現(xiàn)weaving功能的工具。

    發(fā)貼心情?

    AOP與權(quán)限控制實(shí)現(xiàn)

    板橋里人http://www.jdon.com 2004/01/10

      以往在J2EE系統(tǒng)中,訪問(wèn)權(quán)限控制系統(tǒng)的實(shí)現(xiàn)主要有兩種:應(yīng)用程序?qū)崿F(xiàn)和J2EE容器實(shí)現(xiàn)。

    傳統(tǒng)的應(yīng)用程序?qū)崿F(xiàn)

      這是最直接的、傳統(tǒng)的一種解決方式,通常是在具體方法前加一個(gè)權(quán)限判斷語(yǔ)句,如下:

    public class ForumFactoryProxy extends ForumFactory {
      ......
      public Forum createForum(String name, String description)
        throws UnauthorizedException, ForumAlreadyExistsException
      {
        if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
          Forum newForum = factory.createForum(name, description);
          return new ForumProxy(newForum, authorization, permissions);
        }else {
          throw new UnauthorizedException();
        }
      }
      ......
    }

      上述代碼是Jive論壇中一段創(chuàng)建論壇功能的代碼,在創(chuàng)建論壇前,首先進(jìn)行權(quán)限角色檢驗(yàn),如果當(dāng)前用戶是系統(tǒng)管理員,那么可以實(shí)現(xiàn)真正的創(chuàng)建。

      這種在具體功能前加入權(quán)限操作檢驗(yàn)的實(shí)現(xiàn)方式有很多缺點(diǎn):
      1.每個(gè)功能類都需要相應(yīng)的權(quán)限檢驗(yàn)代碼,將程序功能和權(quán)限檢驗(yàn)混淆在一起,存在緊密的耦合性,擴(kuò)展修改難度大。
      2.如果類似Jive,以代理模式為每個(gè)功能類實(shí)現(xiàn)一個(gè)相應(yīng)的代理類,雖然解耦了程序功能和權(quán)限檢驗(yàn),但是,從某個(gè)角色的權(quán)限檢驗(yàn)這個(gè)切面考慮,涉及具體Proxy類太多,擴(kuò)展修改難度大。

    J2EE容器實(shí)現(xiàn)

      在AOP概念沒有誕生前,J2EE規(guī)范已經(jīng)提供了關(guān)于權(quán)限控制的容器實(shí)現(xiàn)標(biāo)準(zhǔn),這種變遷結(jié)果如下圖所示:

      原來(lái)需要每個(gè)應(yīng)用程序?qū)崿F(xiàn)的權(quán)限Proxy轉(zhuǎn)為整個(gè)容器的Proxy實(shí)現(xiàn),其中JDK1.3以后的動(dòng)態(tài)代理API為這種轉(zhuǎn)換實(shí)現(xiàn)提供了技術(shù)保證。

      非常明顯,通過(guò)容器實(shí)現(xiàn)權(quán)限控制驗(yàn)證可以大大簡(jiǎn)化應(yīng)用程序的設(shè)計(jì),分離了應(yīng)用系統(tǒng)的權(quán)限關(guān)注,將權(quán)限控制變成了對(duì)J2EE容器服務(wù)器的配置工作,具體技術(shù)細(xì)節(jié)參考我的書籍《Java實(shí)用系統(tǒng)開發(fā)指南》第六章。

      其實(shí),容器的權(quán)限實(shí)現(xiàn)也是一種從一個(gè)切面來(lái)解決問(wèn)題方式,AOP概念誕生后,權(quán)限控制實(shí)現(xiàn)由此也帶來(lái)了兩個(gè)方向的變化:
      1. J2EE容器級(jí)別的權(quán)限實(shí)現(xiàn),也就是容器自身的權(quán)限實(shí)現(xiàn)。
      2. J2EE應(yīng)用程序級(jí)別的權(quán)限實(shí)現(xiàn)。

      權(quán)限控制在容器級(jí)別實(shí)現(xiàn)似乎使得J2EE開發(fā)者感覺沒有靈活性和可擴(kuò)展性,其實(shí)象JBoss 4.0這樣的J2EE容器,由于引入了AOP概念,使得J2EE開發(fā)者在自己的應(yīng)用系統(tǒng)中能夠直接操縱容器的一些行為。容器和應(yīng)用系統(tǒng)由于AOP引入的Aspect切面,變得可以成為一體了。(如果使用BEA的EJBC編輯要浪費(fèi)多少時(shí)間?)

      對(duì)于J2EE應(yīng)用系統(tǒng)開發(fā)者,能夠做到上述境界,必須的條件是對(duì)JBoss之類J2EE容器必須有足夠的了解,因?yàn)檫@些方式并不是J2EE標(biāo)準(zhǔn),有可能在移植到新的J2EE容器,這些知識(shí)和投入變得無(wú)用(也有可能將來(lái)J2EE擴(kuò)展其標(biāo)準(zhǔn))。

      很顯然,使用AOP實(shí)現(xiàn)J2EE應(yīng)用系統(tǒng)級(jí)別的權(quán)限控制,是解決上述移植風(fēng)險(xiǎn)的一個(gè)主要方法,但是帶來(lái)的缺點(diǎn)是必須親自從零開始做起,耗費(fèi)時(shí)間不會(huì)很短。

    AOP下的應(yīng)用程序權(quán)限控制實(shí)現(xiàn)

      引入AOP概念后的權(quán)限實(shí)現(xiàn)已經(jīng)不是前面Jive實(shí)例那樣“落后”,我們對(duì)這個(gè)實(shí)例進(jìn)行重整(Refactorying)如下:

    創(chuàng)建一個(gè)Aspect,專門用于權(quán)限檢查,如下:

    private static aspect PermissionCheckAspect {

      private pointcut permissionCheckedExecution() :
       execution ( public Forum ForumFactory.createForum(String , String ));

      before () : permissionCheckedExecution() {
        if !(permissions.get(ForumPermissions.SYSTEM_ADMIN)) {
          throw new UnauthorizedException();
        }
       }

    }

    該段代碼功能是:當(dāng)系統(tǒng)運(yùn)行ForumFactory.createForum方法之前,將首先檢查是否有權(quán)限操作。

    代碼中pointcut觸發(fā)的條件是createForum方法執(zhí)行,如果有其它需要系統(tǒng)管理員身份才能執(zhí)行的方法加入,將寫成如下代碼:

    private pointcut permissionCheckedExecution() :
       execution ( public Forum ForumFactory.createForum(String , String )) ||
       execution ( public Forum ForumFactory.deleteForum(String , String )) ||
       ......
       execution ( public Forum ForumFactory.deleteThread(String , String ));

    這些方法陳列比較瑣碎,依據(jù)AspectJ語(yǔ)法,可以簡(jiǎn)化如下:
    private pointcut permissionCheckedExecution() :
       execution ( public * ForumFactory .*(..));

    有興趣者可以將Jive論壇中相關(guān)權(quán)限Proxy部分使用AOP重整,另外,由于Jive沒有引入角色概念,導(dǎo)致權(quán)限和用戶HardCode在編碼中,如何實(shí)現(xiàn)權(quán)限和用戶解耦,最小限度的降低HardCode量,角色概念在其中起著不可忽視的重要作用。這是另外一個(gè)研究課題了。

    發(fā)貼心情?

    Ioc模式

    板橋里人http://www.jdon.com 2004/01/31

      分離關(guān)注( Separation of Concerns : SOC)是Ioc模式和AOP產(chǎn)生最原始動(dòng)力,通過(guò)功能分解可得到關(guān)注點(diǎn),這些關(guān)注可以是 組件Components, 方面Aspects或服務(wù)Services。

      從GoF設(shè)計(jì)模式中,我們已經(jīng)習(xí)慣一種思維編程方式:Interface Driven Design 接口驅(qū)動(dòng),接口驅(qū)動(dòng)有很多好處,可以提供不同靈活的子類實(shí)現(xiàn),增加代碼穩(wěn)定和健壯性等等,但是接口一定是需要實(shí)現(xiàn)的,也就是如下語(yǔ)句遲早要執(zhí)行:

      AInterface a = new AInterfaceImp();

      AInterfaceImp是接口AInterface的一個(gè)子類,Ioc模式可以延緩接口的實(shí)現(xiàn),根據(jù)需要實(shí)現(xiàn),有個(gè)比喻:接口如同空的模型套,在必要時(shí),需要向模型套注射石膏,這樣才能成為一個(gè)模型實(shí)體,因此,我們將人為控制接口的實(shí)現(xiàn)成為“注射”。

      Ioc英文為 Inversion of Control,即反轉(zhuǎn)模式,這里有著名的好萊塢理論:你呆著別動(dòng),到時(shí)我會(huì)找你。

      其實(shí)Ioc模式也是解決調(diào)用者和被調(diào)用者之間的一種關(guān)系,上述AInterface實(shí)現(xiàn)語(yǔ)句表明當(dāng)前是在調(diào)用被調(diào)用者AInterfaceImp,由于被調(diào)用者名稱寫入了調(diào)用者的代碼中,這產(chǎn)生了一個(gè)接口實(shí)現(xiàn)的原罪:彼此聯(lián)系,調(diào)用者和被調(diào)用者有緊密聯(lián)系,在UML中是用依賴 Dependency 表示。

      但是這種依賴在分離關(guān)注的思維下是不可忍耐的,必須切割,實(shí)現(xiàn)調(diào)用者和被調(diào)用者解耦,新的Ioc模式 Dependency Injection 模式由此產(chǎn)生了, Dependency Injection模式是依賴注射的意思,也就是將依賴先剝離,然后在適當(dāng)時(shí)候再注射進(jìn)入。

    Ioc模式(Dependency Injection模式)有三種:

    第一種類型從JNDI或ServiceManager等獲得被調(diào)用者,這里類似ServiceLocator模式。1. EJB/J2EE
    2. Avalon(Apache的一個(gè)復(fù)雜使用不多的項(xiàng)目)
    第二種類型使用JavaBeans的setter方法1. Spring Framework,
    2. WebWork/XWork
    第三種類型在構(gòu)造方法中實(shí)現(xiàn)依賴1. PicoContainer,
    2. HiveMind

      有過(guò)EJB開發(fā)經(jīng)驗(yàn)的人都知道,每個(gè)EJB的調(diào)用都需要通過(guò)JNDI尋找到工廠性質(zhì)的Home接口,在我的教程EJB是什么章節(jié)中,我也是從依賴和工廠模式角度來(lái)闡述EJB的使用。

      在通常傳統(tǒng)情況下,為了實(shí)現(xiàn)調(diào)用者和被調(diào)用者解耦,分離,一般是通過(guò)工廠模式實(shí)現(xiàn)的,下面將通過(guò)比較工廠模式和Ioc模式不同,加深理解Ioc模式。

    工廠模式和Ioc

      假設(shè)有兩個(gè)類B 和 C:B作為調(diào)用者,C是被調(diào)用者,在B代碼中存在對(duì)C的調(diào)用:

    public class B{
       private C comp;
      ......
    }

      實(shí)現(xiàn)comp實(shí)例有兩種途徑:?jiǎn)螒B(tài)工廠模式和Ioc。

    工廠模式實(shí)現(xiàn)如下:

    public class B{
       private C comp;
      private final static MyFactory myFactory = MyFactory.getInstance();

      public B(){
        this.comp = myFactory.createInstanceOfC();

      }
       public void someMethod(){
        this.comp.sayHello();
      }
      ......
    }

    特點(diǎn):

    • 每次運(yùn)行時(shí),MyFactory可根據(jù)配置文件XML中定義的C子類實(shí)現(xiàn),通過(guò)createInstanceOfC()生成C的具體實(shí)例。

    使用Ioc依賴性注射( Dependency Injection )實(shí)現(xiàn)Picocontainer如下,B類如同通常POJO類,如下:

    public class B{
       private C comp;
      public B(C comp){
        this.comp = comp;
       }
       public void someMethod(){
        this.comp.sayHello();
       }
      ......
    }

    假設(shè)C接口/類有有一個(gè)具體實(shí)現(xiàn)CImp類。當(dāng)客戶端調(diào)用B時(shí),使用下列代碼:

    public class client{
       public static void main( String[] args ) {
        DefaultPicoContainer container = new DefaultPicoContainer();
        container.registerComponentImplementation(CImp.class);
        container.registerComponentImplementation(B.class);
        B b = (B) container.getComponentInstance(B.class);
        b.someMethod();
       }
    }

      因此,當(dāng)客戶端調(diào)用B時(shí),分別使用工廠模式和Ioc有不同的特點(diǎn)和區(qū)別:

      主要區(qū)別體現(xiàn)在B類的代碼,如果使用Ioc,在B類代碼中將不需要嵌入任何工廠模式等的代碼,因?yàn)檫@些工廠模式其實(shí)還是與C有些間接的聯(lián)系,這樣,使用Ioc徹底解耦了B和C之間的聯(lián)系。

      使用Ioc帶來(lái)的代價(jià)是:需要在客戶端或其它某處進(jìn)行B和C之間聯(lián)系的組裝。

      所以,Ioc并沒有消除B和C之間這樣的聯(lián)系,只是轉(zhuǎn)移了這種聯(lián)系。
      這種聯(lián)系轉(zhuǎn)移實(shí)際也是一種分離關(guān)注,它的影響巨大,它提供了AOP實(shí)現(xiàn)的可能。

    Ioc和AOP

      AOP我們已經(jīng)知道是一種面向切面的編程方式,由于Ioc解放自由了B類,而且可以向B類實(shí)現(xiàn)注射C類具體實(shí)現(xiàn),如果把B類想像成運(yùn)行時(shí)的橫向動(dòng)作,無(wú)疑注入C類子類就是AOP中的一種Advice,如下圖:

      通過(guò)下列代碼說(shuō)明如何使用Picocontainer實(shí)現(xiàn)AOP,該例程主要實(shí)現(xiàn)是記錄logger功能,通過(guò)Picocontainer可以使用簡(jiǎn)單一行,使所有的應(yīng)用類的記錄功能激活。

    首先編制一個(gè)記錄接口:

    public interface Logging {

      public void enableLogging(Log log);

    }

    有一個(gè)LogSwitcher類,主要用來(lái)激活具體應(yīng)用中的記錄功能:

    import org.apache.commons.logging.Log;
    public class LogSwitcher
    {
      protected Log m_log;
      public void enableLogging(Log log) {
        m_log = log;
        m_log.info("Logging Enabled");
      }
    }

    一般的普通應(yīng)用JavaBeans都可以繼承這個(gè)類,假設(shè)PicoUserManager是一個(gè)用戶管理類,代碼如下:

    public class PicoUserManager extends LogSwitcher
    {

      ..... //用戶管理功能
    }
    public class PicoXXXX1Manager extends LogSwitcher
    {

      ..... //業(yè)務(wù)功能
    }
    public class PicoXXXX2Manager extends LogSwitcher
    {

      ..... //業(yè)務(wù)功能
    }

    注意LogSwitcher中Log實(shí)例是由外界賦予的,也就是說(shuō)即將被外界注射進(jìn)入,下面看看使用Picocontainer是如何注射Log的具體實(shí)例的。


    DefaultPicoContainer container = new DefaultPicoContainer();
    container.registerComponentImplementation(PicoUserManager.class);
    container.registerComponentImplementation(PicoXXXX1Manager.class);
    container.registerComponentImplementation(PicoXXXX2Manager.class);
    .....

    Logging logging = (Logging) container.getComponentMulticaster();

    logging.enableLogging(new SimpleLog("pico"));//激活log

      由上代碼可見,通過(guò)使用簡(jiǎn)單一行l(wèi)ogging.enableLogging()方法使所有的應(yīng)用類的記錄功能激活。這是不是類似AOP的advice實(shí)現(xiàn)?

      總之,使用Ioc模式,可以不管將來(lái)具體實(shí)現(xiàn),完全在一個(gè)抽象層次進(jìn)行描述和技術(shù)架構(gòu),因此,Ioc模式可以為容器、框架之類的軟件實(shí)現(xiàn)提供了具體的實(shí)現(xiàn)手段,屬于架構(gòu)技術(shù)中一種重要的模式應(yīng)用。J道的JdonSD框架也使用了Ioc模式。




    posted on 2006-06-01 09:42 TrampEagle 閱讀(468) 評(píng)論(0)  編輯  收藏 所屬分類: java
    主站蜘蛛池模板: 国产黄色片免费看| 免费观看四虎精品国产永久| h视频免费高清在线观看| 亚洲精品综合在线影院| 久久精品国产亚洲AV麻豆不卡 | 日木av无码专区亚洲av毛片| 免费少妇a级毛片人成网| 久久这里只有精品国产免费10| a级片免费在线播放| 日韩在线视频线视频免费网站| 亚洲成a人片在线观看精品| 7777久久亚洲中文字幕蜜桃| 国产成人麻豆亚洲综合无码精品| 亚洲av成人一区二区三区在线观看 | 人人鲁免费播放视频人人香蕉| 亚洲精品动漫免费二区| 亚洲av永久无码精品天堂久久 | 精品免费视在线观看| 一个人看的免费视频www在线高清动漫 | 亚洲欧美成人一区二区三区| 亚洲国产精品成人精品软件| 精品日韩亚洲AV无码一区二区三区 | 国产免费高清69式视频在线观看| 亚洲日韩一区二区三区| 亚洲免费在线观看视频| 婷婷久久久亚洲欧洲日产国码AV | 国产亚洲福利在线视频| 亚洲国产精品日韩在线观看 | 国产精品1024永久免费视频| 91短视频在线免费观看| 久久综合给合久久国产免费| 三年片在线观看免费观看大全一| a在线免费观看视频| 在线涩涩免费观看国产精品| 国内精品99亚洲免费高清| 国产人成网在线播放VA免费| 国产成人AV免费观看| 久久免费高清视频| 99re免费99re在线视频手机版| 99re视频精品全部免费| 久草在视频免费福利|