天天看點

使用 AOP 陷阱之一

    手頭上的一個項目使用了Spring.net的AOP了處理程式的異常,一不小心就掉進了陷阱,這裡記錄下來,希望對後來者有所幫助。Spring.net的AOP實作是通過運作時建立動态的AOP代理來完成的。簡單圖示如下:

使用 AOP 陷阱之一

    圖中的“POJO”以詞來自Java,表示一個普通的.net對象,所有對POJO的調用都要經過Aop代理進行,是以Aop才有機會插入Pre_Action、Post_Action、和Around_Action。

    現在我以手上的工作舉個例子,看我是如何掉入陷阱的:

    public interface IIrasRemotingServiceAccesser

    {

        void Initialize() ;

        void fsManager_AsServiceListChanged(int serverID, string serverName, ArrayList serviceList) ;

        void CheckMySelf() ;

     }

    我們沒有必要了解IIrasRemotingServiceAccesser接口的具體用途,隻要了解這個接口将被Aop代理,為了使Aop能夠截獲fsManager_AsServiceListChanged方法,我把它放入了接口定義中,實際上它是一個事件處理函數,本應是私有的。

    Initialize方法使用fsManager_AsServiceListChanged預定了某個事件:

        public void Initialize()

        {                

            this.fsManager.AsServiceListChanged += new CbServiceChanged(fsManager_AsServiceListChanged);

        }

    運作程式後,發現CheckMySelf方法能正常被AOP截獲,而當fsManager.AsServiceListChanged事件發生時,對fsManager_AsServiceListChanged的調用沒有被截獲。

    這是為什麼?

    原來是預定事件時,繞過了AOP代理:

            this.fsManager.AsServiceListChanged += new CbServiceChanged(this.fsManager_AsServiceListChanged);

    請注意紅色的“this”,正是它繞過了AOP代理。是以fsManager_AsServiceListChanged的調用沒有被截獲。解決方案?我常用的有兩種:

(1)将this換為代理:

        {

            IIrasRemotingServiceAccesser myAopProxy = (IIrasRemotingServiceAccesser)MainClass.SpringContext.GetObject("irasRemotingServiceAccesser") ;

            this.fsManager.AsServiceListChanged += new CbServiceChanged(myAopProxy.fsManager_AsServiceListChanged);

    可以看到,myAopProxy.fsManager_AsServiceListChanged被委托為事件處理函數,這是通過Aop代理myAopProxy進行。這種方法解決了問題,但是又引入了新的問題--IIrasRemotingServiceAccesser實作類不再是一個“POJO”,而是依賴于Spring.net架構了。更好的辦法是第二種:

        void ChangeServiceList(int serverID, string serverName, ArrayList serviceList) ;

    }

    如此,原來Initialize方法中的事件預定就轉移到Bridge中了,是以就避免了繞過AOP代理的情況。