以前作AgentBooking時候,遇到兩個問題比較棘手,一個是異常的傳遞與捕獲:如何能夠合理地在層層代碼調用中統一傳遞並統一捕獲異常。由於若是有一個作法,能夠地方統一處理異常,可使代碼減小不少try cath邏輯,也不一樣時刻關注該怎麼拋異常,這樣代碼寫起來就比較happy。
第二個是Log的統一記錄。和第一個問題同樣,若是能夠找到一種方法,能夠統一記Log,不用再在代碼中時刻關注何時該怎麼記Log,這確定是一種更好的改進。
上兩個星期去Search了一下AOP(
面向切面編程),其思想很大程度上能夠給咱們提供幫助。AOP大概意思就是說,在代碼的編譯期或者運行期自動爲程序插入額外的功能邏輯。其思想就是將主要業務邏輯和輔助功能分離出來。在MOE中有一個經典的應用場合:每次MOE在調用Web Service時候,都回家RQ序列號並保存到一個txt的Log文件中,因此這個調用webservice的方法既有主要業務邏輯(RQ的生成)的代碼,又有RQ入Log的輔助功能。若是應用AOP,則這個方法中只須要寫主要業務的邏輯,RQ入LOG的邏輯代碼能夠交給AOP框架自動在編譯期動態(或靜態)「插入」到原來的代碼裏面。
AOP實現手段大概有兩種,一是在編譯是對代碼的IL進行分析,而後插入(官方叫「織入」)額外功能的代碼。二是對方法調用進行攔截並執行額外代碼邏輯。
這裏主要介紹一下context與方法攔截。(由於IL涉及到編譯器,太深奧,不明覺厲,而方法攔截除了AOP,感受還能夠用在其餘地方)
在.NET中,每一個App Domain(應用程序域,在.net中一個進程能夠有N個線程,一個線程能夠有N個App Domain)都至少有一個Context,當一個對象被new出來後,就是存在於context中。(我以爲context是更是一種編程思想,就是將資源都放在一個地方。典型的有HttpContext,就集中包含了每一個HttpRequest訪問時的一些信息)。.net程序第一個context是一個默認context,每一個context都有一個ContextID.能夠經過Thread.CurrentContext來訪問當前Context。
.net裏的對象從context的角度能夠分爲兩種:context-aglie object(上下文靈活對象)和context-bound object(上下文綁定對象)。
context-aglie object老是存在於這個對象的調用者所在的context中(我查了一下資料,大概是這個意思,但我尚未驗證過是否是這樣)。對context-aglie object的調用是一種直覺引用,並非經過代理的調用。這個很重要,由於直接的調用是不能被攔截的,只有經過「代理」的調用才能被攔截,見下文。
而另外一種是context-bound object(上下文綁定對象)。若是一個對象繼承了ContextBoundObject ,就成了一個context-bound object。 context-bound object會被強制綁定到一個指定的context中。當一個調用者和被調用的對象處於不一樣的context中時,這個調用不是直接的引用,而是須要經過代理去進行的。正是由於有這個「代理」,才能在調用過程當中作手腳,例如在調用這個對象的一個方法前或調用方法完畢後作一些額外的邏輯(如Log,或者方法執行的時間統計等等),聽起來很熟悉?在HttpModule中也是這種作法。
這裏的「代理」有幾種:遠程代理(Remote Proxy),虛擬代理(Virtual Proxy),智能引用代理(Smart Reference Proxy).在.NET Remoting中,代理又分爲透明代理(Transparent Proxy)和真實代理(Real Proxy)
方法調用的攔截就須要用到透明代理和真實代理。當一個對象調用另外一個context裏的對象(好比說調用該對象的某個方法),這個調用到達透明代理時會被轉換爲一個Message,並將Message傳給Real Proxy。Real Proxy將Message傳到這個對象的過程當中,Message會經歷由N個MessageSink(消息槽)組成的管道中。每一個MessageSink能夠對消息進行處理並再次拋給下一個MessageSink,一直將調用傳遞到那個Object爲止。每一個MessageSink中即是咱們攔截方法調用的地方了。