程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> IoC容器與面向方面編程在SP無線運營系統設計中的應用

IoC容器與面向方面編程在SP無線運營系統設計中的應用

編輯:關於.NET

一直以來,在SP無線運營系統的中關於同步接口的設計由於上下家系統設計的規范不一致,導致這一 部分不能很好的抽象共用,在我近2年來接觸的各方平台接口大部分都是以一個接口作為一個頁面的形式 開放給上下家使用,表現形式只是編程平台的不同,或asp或php等,同一系統各接口的共用部分也多以數 據訪問層為主。

接下來將就我如何應用IoC控制反轉容器和AOP來從技術角度解決這一問題做一個描述。

做無線運營的朋友眾所周知,關於用戶上下行(以短信,彩信,WAP等方式)直到扣費,涉及到的相關 步驟有 預提交,MO同步,MT狀態報告,依業務的不同又有可能沒有預提交(依靠指令分辨下家),MO同 步(MT流程內容控制在SP方),MT狀態報告(如SP直接同步狀態報告,MT報告就以MO同步形式表現)。

因此這裡我首先抽象出三個對象, 分別是 ApiRequest表示預提交原始信息(包括號碼,下家ID,附 加參數等),ApiSync表示MO同步的原始信息(包括號碼,MO上行內容,LINKID或MOID等), ApiStateReport表示狀態報告原始信息(包括號碼,LINKID,狀態參數等)

理所應當的,有了這些對象自然要有處理這些對象的人(?)和處理結果,接下來再添加一些東西

如圖所示分別添加三個處理器來處理對應的預提交,MO同步以及狀態報告的原始信息對象並返回相應 的處理結果。

經過上面一番步驟,我們有了大體的設計思路,但是應該如何使用它們呢?讓我們跳出來稍微休息一 會談談別的相關話題。

一般所謂的SP接口,不是編程語言裡所謂的Interface,但也有相同之處,無非是調用與被調用雙方實 現約定好參數規范,然後傳輸數據,這一步驟不會涉及到用戶界面之類的UI處理。在WEB環境下我們使 用.NET平台來處理這一問題,很自然的就會想到借助IHttpHandler,沒錯,我們正是需要這位老朋友來幫 助處理問題。

如圖所示,我們有了分別處理預提交,MO同步與MT狀態報告的三個Handler入口。遵循前輩們“組合優 於繼承”的設計原則,我們並沒有讓handler實現相應的invoker接口,而是“擁有”它們,為了我們下一 步的“注入依賴”做好准備。

IApiRequestHandler簡單的實現代碼如下

public interface IApiRequestHandler : IHttpHandler
     {
         IRequestInvoker RequestInvoker { get; set; }
         ApiRequestResult Request(ApiRequest apiRequest);
     }

既然IHttpHandler已然出場,IHttpHandler的老爸IHttpHandlerFactory不出來實在是說不過去了。只 要使用合適的參數,咱們完全可以使用統一的入口來調用預提交,MO同步或是MT狀態報告了。

接下來咱們編程的好幫手IoC容器將第一次入場亮相。。。。。

隨著Spring 的面世,IoC反轉容器在JAVA界迅速得到應用,.NET也很快有相應的實現,比如大家熟知 的Castle項目。在這個應用中我使用了Spring.net的解決方案,程序入口如下面的代碼所示 

ApiHandlerFactory

/// <summary>
     /// API入口(提交,同步,狀態報告)
     /// </summary>
     public class ApiHandlerFactory : IHttpHandlerFactory
     {
         private IHttpHandler handler;
         #region IHttpHandlerFactory Members
         public IHttpHandler GetHandler(HttpContext context, string  requestType, string url, string pathTranslated)
         {
             string type = context.Request.SafeQueryString("type");//擴展方 法SafeQueryString
             IApplicationContext appContext = ContextRegistry.GetContext ();
             handler = appContext[type] as IHttpHandler;

             return handler;
         }
         public void ReleaseHandler(IHttpHandler handler)
         {
             //throw new NotImplementedException();
         }
         #endregion
     }

通過上面大家很容易看出,這裡直接通過提交的參數type來決定最終調用哪個handler來處理上下家同 步過來的數據。

相應的spring配置文件如下 

<!-- 聲明分別實現了IApiRequestInvoker,IApiSyncInvoker,IApiStateReportInvoker的三 個類-->
   <object id="DefaultRequestInvoker" type="Service.ApiService.DefaultRequestInvoker, Service"/>
   <object id="DefaultSyncInvoker" type="Service.ApiService.DefaultSyncInvoker, Service"/>
   <object id="DefaultStateReportInvoker" type="Service.ApiService.DefaultStateReportInvoker, Service"/>
   <!-- 聲明執行預提交動作的實現IApiRequestHandler的類 -->
   <object id="request" type="Api.DefaultRequestHandler,Api">
     <property name="RequestInvoker" ref="DefaultRequestInvoker" />
   </object>
   <!-- 聲明執行MO同步的實現IApiSyncHandler的類 -->
   <object id="sync" type="Api.DefaultSyncHandler,Api">
     <property name="SyncInvoker" ref="DefaultSyncInvoker" />
   </object>
   <!-- 聲明執行接受狀態報告的實現IApiStateReportHandler的類
   <object id="state" type="Api.StateReportHandler,Api">
     <property name="ReportExecutor" ref="SmsStateReportExecutor" />
   </object>
   <!-- 聲明執行電影業務的MO同步的實現IApiSyncHandler的類 -->
   <object id="filmSync" type="ApiExtension.FilmSyncHandler,ApiExtension">
     <property name="SyncInvoker" ref="FilmSyncInvoker" />
   </object>

相應的web.config配置如下

<httpHandlers>
         <add verb="GET,POST" path="entry.aspx" type="Api.ApiHandlerFactory, Api"/>
</httpHandlers>

如此,我們的所有數據處理的接口都通過entry.aspx來進行訪問了,為了避免比如entry.aspx? type=request&spid=xxx這樣的表現形式,我們可以通過使用asp.net mvc或者是url重寫來“美化” 一下。這裡為了方便我直接使用了urlrewritter控件來執行重寫

<rewriter>
<rewrite url="^~/api/request/?\??(.*)" to="~/entry.aspx? type=request&amp;$1" />
<rewrite url="^~/api/(\d+)/(\w+)/?\??(.*)" to="~/entry.aspx? spid=$1&amp;type=$2&amp;$3" />
</rewriter>

這樣一來提供給下家的預提交接口就變成了  http://mysite.com/api/request?@#¥!@¥#! @#¥

提供給SP上家的MO同步和狀態報告地址就變成了  http://mysite.com/api/100/sync 或 http://mysite.com/api/100/state

看起來是不是清爽多了 ?結合相應的數據庫設計,大部分情況下,每次新增接口就不用再寫那沒一點 技術含量的接口頁面了,配置都在後台完成。

如果有人問實在是有個別處理過程十分BT不人道的無線接口,連上面的可擴展設計都無法適用怎麼辦 ?好在咱們還有一把"金剛鑽"——AOP。

咱們還是使用Spring.net的AOP解決方案。

正好,咱們來了一個BT的MO同步接口要處理,解決辦法如下

BT_SyncInterceptor

public class BT_SyncInterceptor : IMethodInterceptor
     {
         #region IMethodInterceptor Members
         public object Invoke(IMethodInvocation invocation)
         {
             HttpContext context = invocation.Arguments[0] as  HttpContext;
             //用以多個通道但必須用一個同步地址的情況 
             if (context != null)
             {
                 if (context.Request["spid"] == "103") //根據spid判斷
                 {
                     //處理bt的業務需求
                 }

                 return invocation.Proceed();
             }
             else 
             {
                 return invocation.Proceed();
             }
         }
         #endregion
     }

相應的spring配置文件的sync對象部分也要改動

<object id="sync" type="Spring.Aop.Framework.ProxyFactoryObject">
     <property name="Target">
       <object type="Api.DefaultSyncHandler, Api" >
         <property name="SyncInvoker" ref="DefaultSyncInvoker" />
       </object>
     </property>
     <property name="InterceptorNames">
       <list>
         <value>BT_SyncInterceptor</value>
       </list>
     </property>
   </object>

<object id="BT_SyncInterceptor" type="AnotherAssembly.BT_SyncInterceptor, AnotherAssembly" />

如上所示,咱們通過修改spring配置文件把這個BT的mo同步接口指向了另一個經過包裝的 DefaultSyncHandler對象,WAPPER就是Spring.Aop.Framework.ProxyFactoryObject,通過裝在另一個程 序集裡的BT_SyncInterceptor類橫切處理相關的業務邏輯,這樣咱們就既保留了原有的處理方式不變來適 應大部分的業務需求,碰到極端的情況,還可以通過第三方組件的形式來進行彌補,正所謂你有張良計我 有AOP,哈。

當然,實際的業務需求比上面所述要復雜的多,這裡展示的只是一個大概的設計框架,實現方法。

謹記,備忘。

PS:對於這類IO密集型的處理,應用異步方式處理應該效率更好,,正在努力學習老趙infoQ裡關於異 步托管的實現方式。。。。。希望有下文描述解決這方面的機會。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved