深刻解析路由系統架構原理

.NET/ASP.NET Routing路由(深刻解析路由系統架構原理)

閱讀目錄:html

  • 1.開篇介紹
  • 2.ASP.NET Routing 路由對象模型的位置
  • 3.ASP.NET Routing 路由對象模型的入口
  • 4.ASP.NET Routing 路由對象模型的內部結構
    • 4.1】UrlRoutingModule 對象內部結構
    • 4.2】RouteBase、Route、RouteCollection、RouteTable 路由核心對象模型
    • 4.3】RouteValueDictionary、RouteData、RequestContext 路由數據對象模型
    • 4.4】IRouteHandler 、IHttpHandler兩個接口之間的關係
  • 5.】UrlRoutingHandler 對象內部結構及擴展應用

1】開篇介紹

這篇文章讓咱們愉快的學習一下ASP.NET中核心的對象模型Routing模塊,爲何說愉快呢,由於Routing正是創建在你們都比較熟悉的ASP.NET管道模型基礎之上的,因此相比其餘一些陌生的概念會輕鬆不少,不過沒關係一回生二回熟;前端

ASP.NET Routing 系統是一切經過ASP.NET進行Uri訪問應用程序的基礎(並不是物理文件的直接映射);隨着Routing的出現,咱們的WEB設計已經和之前大不同;愈來愈輕量級、簡單化,都經過簡便的Uri資源的方式進行處理,將精力放在業務的設計上;如今主流的Rest ful api 也都是創建在這樣的一種機制下的,然而咱們的ASP.NETMVC也是一種經過獨立的Uri進行程序訪問處理的框架,因此也是創建在ASP.NET Routing;再者就是如今也比較熱門的ASP.NET技術(ASP.NETWEBAPI);都是創建在Routing框架之上,可見它仍是蠻重要的;web

因此這篇文章讓咱們來分析一下Routing的工做原理,它爲何能在不影響現有框架的基礎上提供這麼好的擴展性,真的讓人很想去一探究竟;目前很是可觀是咱們都瞭解ASP.NET現有的框架知識,咱們大概瞭解它確定是在ASP.NET管道模型的哪一個位置進行了相應的攔截;數據庫

下面咱們帶着這個重要的線索來一點一點弄清楚它是如何爲其餘框架作支撐的,我最疑惑的是它是如何將WebPage和MVC進行很好的區分的 ,最關鍵的是它如何作到只提供一個接口讓後續的相關框架都能基於這個公共的Routing接口進行擴展的,它的對象模型確定很巧妙;咱們須要去搞懂它,纔能有信心去繼續咱們的ASP.NET相關框架的後續學習;編程

注意:全文使用Routing一詞替代ASP.NETRouting一詞,特此說明,以避免概念混淆;api

2】ASP.NETRouting路由對象模型的位置

問到ASP.NET最重要的擴展點在哪裏?我想咱們都會異口同聲的說:在管道模型上,這也符合咱們對此問題求解的一個基本思路;ASP.NET管道模型你們都懂的,在管道模型的相關事件中只要咱們定義相關的事件就能夠在管道的處理中插入本身的邏輯在裏面;管道的最後執行接口是IHttpHander類型,只有阻止本來默認的IHttpHander接口建立纔有可能改變整個的處理流程;安全

圖2.1:多線程

那麼Routing只有在阻止IHttpHander接口的建立前先執行,才能扭轉整個處理路線的機會,上圖中顯示的Application Event(2)(IHttpHander執行)意思是說只有在IHttpHander執行前的某個Application Event中進行Routing的執行才能在本來執行IHttpHander的地方執行其餘定製的IHttpHander;而IHttpHander是ASP.NET框架的最終執行的接口,因此若是要想改變本來執行Page的Hander,須要提供自定義的IHttpHander接口對象;架構

換句話說,一切的執行入口其實在IHttpHander.ProcessRequest()方法中,可是如今矛盾的是ASP.NET Routing 卡在中間,它讓本來直接的處理流程變的有點撲簌迷離,它隔開了「ASP.NET基礎框架 " 與 "基於ASP.NET的應用框架 "(如:ASP.NETMVC\ASP.NETWEBAPI\自定義框架)併發

注意:「ASP.NET基礎框架」指ASP.NET自己的框架能夠理解爲傳統的WEBFROM;而「基於ASP.NET的應用框架」是指基於ASP.NET基礎框架而設計的如:MVC\WEBPAGE\WEBAPI之類的上層輕量級應用框架;

圖2.2:

其實這幅圖很明瞭的表達式了ASP.NETRouting的位置,它是用來爲ASP.NETASP.NETMVC、ASP.NETWEBAPI承上啓下的關鍵紐帶;根據上面咱們的分析思路,Routing是ASP.NET框架直接交互的對象模型,因此站在ASP.NET的角度它是不知道背後究竟發生了什麼事情,其實ASP.NETRouting已經在ASP.NETApplication某個生命事件中將本來的建立邏輯移花接木了;

3.】ASP.NETRouting路由對象模型的入口

Routing起到中間人的做用,將ASP.NET的相關邏輯透明包裝,咱們雖然能在Routing的上層一樣可使用相關的ASP.NET對象,可是概念已經發生了根本上的變化;咱們能夠隨意的引入自定義的IHttpHander實現類,根據前端傳過來的Uri進行策略執行,也就是說你徹底能夠定義一套本身內部使用的Uri規則和處理框架,創建在Routing基礎之上會很容易;

根據IHttpModule、IHttpHander 的相關的知識,咱們很容易就能知道從哪裏能夠找到Routing的入口線索,若是咱們都沒有猜錯的話在系統的Web.config文件中確定有一個專門處理Routing的IHttpModule,利用來它將ASP.NETRouting對象植入到ASP.NET框架之中;

咱們找到.NET Framework環境配置的地方:C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config 在該文件中咱們能夠找到系統級別的配置信息;

其實這裏面配置的都是系統級別的選項,而咱們程序裏面使用的Web.config文件只是用來配置跟應用程序相關的選項,這樣的好處是咱們能夠在應用程序級別很方便的改變系統的默認配置;

咱們找到httpModules配置節,在倒數第二行發現一個nameUrlRoutingModule-4.0IHttpModule配置,應該就是它了,最關鍵的是它的type信息是System.Web.Routing.UrlRoutingModule 毋庸置疑了;

如今就好辦多了,咱們只要順藤摸瓜就能找到UrlRoutingModule是如何工做的了,不過先不能急,還有些思路並不清晰,咱們繼續慢慢分析;按照這樣的一個思路,基本上咱們能夠判定UrlRoutingModule就是協調ASP.NETRouting框架的紐帶;

圖3.1:

此圖總結了咱們到目前爲止的一個基本思路,底層ASP.NET框架處理HTTP的對象化,而後經過ASP.NETRouting Module建立IHttpHandler接口對象,再而後就是執行IHttpHander接口,共三個步驟;

做爲應用框架也就是最上層的代碼,如何才能決定ASP.NETRouting框架在處理ASP.NET的調用的時候能使用本身的IHttpHander接口對象,這個問題就須要咱們深刻的看一下ASP.NETRouting路由對象的內部對象模型了;

4.】ASP.NETRouting路由對象模型的內部結構

這裏我將使用ASP.NETMVC做爲應用框架來說解本例(目前我並不瞭解ASP.NETWEBAPI);那麼ASP.NETMVC做爲應用層框架,是如何讓ASP.NETRouting幫助轉換IHttpHander接口的呢,這就不得不去分析Routing一些列的對象之間的組成關係及互相做用了;

根據3.】小節,咱們已經瞭解ASP.NETRouting是使用UrlRoutingModuel對象來做爲ASP.NET管道的監聽者,而後根據一系列的內部處理得出最終的IHttpHander接口對象;那麼要想搞清楚UrlRoutingModule是如何具體的協調這一切的,必須得深刻的去分析源代碼才行,儘管咱們只須要了解一個80%那也少不了這個環節;

注意:須要源代碼的朋友能夠直接去一下站點獲取,微軟官方開源網站:http://www.codeplex.com/,開源中國:http://www.oschina.net/均可以找到源代碼;

4.1】UrlRoutingModule對象內部結構

首當其衝須要搞清楚的就是UrlRoutingModule對象,根據源碼指示咱們基本上能肯定幾個基本的原理,首先UrlRoutingModule繼承自IHttpModule接口,訂閱了Application.PostResolveRequstCache事件,在該事件中主要是經過全局路由對象表RouteTable對象獲取提供給上層使用的依賴注入接口IRouteHander接口;

【依賴注入接口】

這裏須要解釋一下什麼叫依賴注入接口,能夠簡單的將依賴注入接口理解成提供給外界一個具體實現的機會;其實就是設計原則中的「依賴倒置原則」,在RouteData的內部不是直接依賴具體的對象;接口就是契約,提供一個接口就是約定雙方之間的契約;這裏是約定了Routing框架將使用IRouteHander接口來獲取最後的處理IHttpHander接口;

下面咱們將對UrlRoutingModule對象進行分析,因爲咱們分析源代碼是想搞清楚對象模型之間的操做流程及關係,因此不可能分析全部的代碼,咱們的重點是搞清楚他們的執行順序及原理;因爲UrlRoutingModule對象是導火線,它的出現將連續不斷的牽連其餘的對象出現,咱們將分小節進行分析,交界處將一帶而過;

根據咱們前面的分析思路,咱們首先要找到UrlRoutingModule綁定Application事件的地方;

1
2
3
4
protected  virtual  void  Init (HttpApplication application)
         {
             application.PostResolveRequestCache += PostResolveRequestCache;
         }

在PostResolverRequestCache方法中,咱們將看到該方法調用了本地內部的一個同名方法:

1
2
3
4
5
void  PostResolveRequestCache ( object  o, EventArgs e)
         {
             var  app = (HttpApplication) o;
             PostResolveRequestCache ( new  HttpContextWrapper (app.Context));
         }

而後實例化了一個HttpContextWrapper包裝對象,傳入該同名方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public  virtual  void  PostResolveRequestCache (HttpContextBase context)
         {
 
             var  rd = RouteCollection.GetRouteData (context);
 
            //(1)匹配RouteData對象,後面分析;
 
             var  rc = new  RequestContext (context, rd);
 
             //(2)封裝計算出來的RouteData對象和當前HttpRequest對象;
 
             IHttpHandler http = rd.RouteHandler.GetHttpHandler (rc);
 
             //(3)使用(1)步驟計算出來的當前RouteData對象中的RouteHander屬性獲取路由處理程序IHttpHander接口;
 
             context.Request.RequestContext = rc;
             context.RemapHandler (http);
 
        }

固然我已經省略了部分不太相關的代碼,畢竟要想說清楚全部的代碼一篇文章顯然是不夠的;上述代碼中我用紅色標記出重要的部分;

首先是第一個重要點(1),匹配RouteData對象;其實就是咱們在程序裏面配置的Url模板數據,當請求來的時候咱們須要去根據當前請求的Url到路由表去匹配是否有符合當前Url的路由對象;

1
2
3
4
routes.MapRoute(
                 name: "Default" ,
                 url: "{controller}/{action}/{id}" ,
                 defaults: new  { controller = "Home" , action = "Index" , id = UrlParameter.Optional }

其實就是對應着本段代碼的配置,這段代碼處理後將是一個Route對象實例,而上面的RouteCollection就很好理解了,它是Route的強類型集合;

到目前爲止,已經出現了好幾個跟Route相關的對象,不要緊,當咱們將整條線分析到頭時將很清楚他們的做用;

第二個重要點(2),封裝RequestContext對象,其實咱們從類型的名稱上就能肯定它的用途,它是請求上下文,也是有界上下文;這裏面封裝了在下面獲取IHttpHander接口時將須要看成參數;

第三個重點(3),利用前面的匹配獲得的RouteData對象,其實RouteData是路由數據的意思,那麼什麼叫路由數據:就是路由匹配成功後所生成的和路由相關的數據;還記得咱們在3】節分析的原理嗎,UrlRoutingModule對上層提供基本的路由功能,可是具體的處理是在應用層面上;

那麼就是這裏經過RouteData.RouteHandler.GetHttpHandler(RequestContext requestContext) 方法獲取到的最終頂層應用處理器;

圖4.1:

上面的解釋可使用這幅圖來簡單的表達;

UrlRoutingModule對象經過RouteData路由數據對象獲取IRouteHander接口,而後經過IRouteHander接口獲取最終的IHttpHander接口;

小結:其實能夠將UrlRoutingModule對象理解成是ASP.NETRouting模塊的基礎部分,而擴展的地方則在咱們應用程序配置的地方,也就是咱們一般在Global.asax.cs文件中配置的路由數據;當咱們在配置Route對象的時候其實已經指定了IRouteHander接口,而後這個接口會被放入RouteData同名屬性中,而不是做爲零散的對象被UrlRoutingModule直接獲取;

4.2】RouteBase、Route、RouteCollection、RouteTable路由核心對象模型

在4.1 】節中,UrlRoutingModule是路由框架的基礎設施部分,內置於. NETFramework系統及ASP.NET配置之中web.config;在ASP.NET進行版本升級的時候該部分工做已經由系統自動幫咱們升級,咱們在使用的時候只須要建立ASP.NET3.5 SP1以上的版本都會自動擁有路由系統功能,由於根據微軟官方MSDN介紹,路由系統是在ASP.NET3.5 SP1中引入的;其實咱們大部分使用的ASP.NET版本已是4.5的,就算之前是2.0、3.0的版本也會陸續升級到最新的版本;由於新版本的框架提供了無數個讓你沒法拒絕的優點;

那麼當基礎部分有了以後咱們能作到就是應用編程接口的編程,其實這部分纔是咱們接觸的地方;而這一小節咱們將重點分析路由系統提供給咱們應用層面的編程接口,也就是上面標題列出的幾個核心對象;

先基本介紹一下這幾個對象的意思和彼此之間的關係:

RouteBase:很明顯是Route的基類,提供了做爲自定義路由對象的頂層抽象,全部的路由框架的內部均使用抽象的RouteBase爲依賴;

Route:路由系統默認實現的路由對象繼承自RouteBase抽象基類,用來做爲咱們默認的路由配置對象,固然你能夠但是實現本身的Route對象;

RouteCollection:Route做爲單個Url的配置,那麼系統中確定會有多個Url規則的配置,因此RouteCollection對象是表示Route的強類型集合,該類繼承自 Collection<RouteBase> 類型;因此RouteCollection是用來做爲Route的集合管理用的;注意這裏的泛型Collection<T>中的RouteBase,再一次提醒咱們要「依賴倒置」;

RouteTable:用來存放RouteCollection對象,路由表中有一系列的路由對象,而這一系列的對象就是RouteCollection管理的;在RouteTable中用Routes靜態屬性表示當前系統全局的路由映射表;

這裏很明顯能看出來對路由的一層一層抽象,從簡單的Route表示一個路由映射,再到表示Route的集合RouteCollection,再到最後的RouteTable的,抽象的很OO;

爲了讓你們對上面這些對象的解釋有一個直觀的認識,咱們用一張圖來解釋他們如何關聯和執行流程;

圖4.2:

下面咱們將深刻到各個對象的內部去摸索一下他們之間的交互,咱們根據這種引用關係來分析,首先是Route對象;

【Route、RouteBase】

Route對象繼承自RouteBase表明一個Url模板的配置,包括Url的模板的字符串,如:api/order/102304,還有一些輔助性的內容,這不是本節的重點,咱們只要知道它是用來作Url的配置便可; Route對象不是直接被咱們實例化的,而是經過應用層的擴展方法進行實例化,爲何要這麼作,其實這裏就是路由爲何能轉到上層的關鍵點;

根據ASP.NETMVC中的路由集合擴展類,也就是System.Web.Mvc.RouteCollectionExtensions靜態類中的擴展方法,這些擴展方法就是用來包裝咱們在應用ASP.NET的時候配置Route使用的;是否還記得咱們第4】節的一開始介紹了一個依賴注入接口的原理,這裏將經過依賴注入接口達到外掛自定義實現的目的;

在Route源碼中,咱們將看到它有一個IRouteHander接口類型的屬性RouteHander;

1
2
3
4
5
public  class  Route : RouteBase
{
 
public  IRouteHandler RouteHandler { get ; set ; }
}

這個IRouteHandler接口類型的屬性就是咱們ASP.NETMVC將要實現的一個IRouteHandler接口;而這個接口的定義:

1
2
3
4
public  interface  IRouteHandler
{
     IHttpHandler GetHttpHandler (RequestContext requestContext);
}

很簡單,就是爲了建立出ASP.NET管道引擎最後執行的IHttpHandler接口; Route類有一個重寫了RouteBase的核心方法:

1
public  override  RouteData GetRouteData (HttpContextBase httpContext)

該方法是用來獲取當前路由的一些匹配數據的,關於RouteData在4.1】節介紹過,詳細咱們將看下面關於對它的詳細分析,這裏將不作介紹了;

小結:其實Route對象還算簡單,關鍵的兩點就是GetRouteData方法和IRouteHander接口,前者是用來獲取當前路由匹配成功後的路由信息,然後者是用來返回最終要執行的IHttpHandler接口;

【RouteCollection、RouteTable】

RouteCollecton和RouteTable對象比較簡單;咱們先來看RouteCollection對象,首先你可能會有疑問,爲何不用一個簡單的Collection類型的對象來存放Route實例,非要實現了一個RouteCollection;不看源碼還真不知道它內部作了不少工做,首先最重要的就是線程併發狀況下的Look機制;因爲咱們的RouteCollection對象是全局靜態對象,會同時存在着多個線程併發的讀取這個對象,因此必須在對集合訪問的時候進行互斥控制;好比說這段代碼:

1
2
3
4
5
6
7
8
public  void  Add ( string  name, RouteBase item)
{
     lock  (GetWriteLock ()) {
         base .Add (item);
         if  (!String.IsNullOrEmpty (name))
             d.Add (name, item);
     }
}

在添加路由的時候首先鎖住寫入對象,而後才能安全的進行操做;咱們接着RouteTable對象,這個對象最簡單,就是一個靜態屬性Routes用來存放全局路由表;

1
2
3
4
5
6
7
8
9
public  class  RouteTable
{
     static  RouteTable ()
     {
         Routes = new  RouteCollection ();
     }
 
     public  static  RouteCollection Routes { get ; private  set ; }
}

當首次獲取Routes屬性時,會在靜態構造函數中實例化RouteCollection對象;

4.3】RouteValueDictionary、RouteData、RequestContext 路由數據對象模型

在第4.2】小節中,咱們分析了路由系統的幾個核心對象,可是核心對象要想運行起來中間必須有一些數據封裝的對象爲他們消除數據傳遞的問題;而這小節的三個核心對象真是路由系統能成功工做的必不可少的數據存放、數據傳輸容器的核心對象;

先基本介紹一下這幾個對象的意思和彼此之間的關係:

RouteValueDictionary:路由對象內部存放中間值使用的對象,好比Url模板的默認值,命名空間,地址欄傳過來的參數等等;固然也能夠用來存聽任何Key-Value形式的任何值;

RouteData:路由數據,用來包裝根據路由Url匹配成功後的路由數據封裝,最重要的是將IRouteHander接口傳遞到UrlRoutingModule中去;

RequestContext:請求上下文,將HttpRequest、RouteData包裝起來傳入IRouteHander接口獲取IHttpHander接口;由於IRouteHandler接口方法GetHttpHandler須要知道當前請求的一些信息和根據當前Url處理後的路由數據才能計算出當前的IHttpHandler接口;

爲了讓你們對上面這些對象的解釋有一個直觀的認識,咱們用一張圖來解釋他們如何關聯和執行流程;

圖4.3:

下面詳細的分析每一個對象的內部原理;

【RouteValueDictionary】

RouteValueDirctionary對象是在路由對象內部存放數據用的,好比:咱們在配置路由的時候,能夠指定一些默認值、命名空間等等;

看RouteValueDictionary源碼定義:

1
public  class  RouteValueDictionary : IDictionary< string , object >

該類型繼承自字典接口IDictionary<string,object>,繼承自字典接口而不是繼承自字典基類目的只是想使用字典的行爲而不是它的默認實現;在RouteValueDictionary內部使用了一個Dictionary<string,object>類型做爲最終容器;

1
Dictionary< string , object > d = new  Dictionary< string , object > (CaseInsensitiveStringComparer.Instance);

在構造函數中使用了一個內部類CaseInsensitiveStringComparer進行Key的相等比較:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
internal  class  CaseInsensitiveStringComparer : IEqualityComparer< string >
         {
             public  static  readonly  CaseInsensitiveStringComparer Instance = new  CaseInsensitiveStringComparer ();
 
             public  int  GetHashCode ( string  obj)
             {
                 return  obj.ToLower (CultureInfo.InvariantCulture).GetHashCode ();
             }
 
             public  bool  Equals ( string  obj1, string  obj2)
             {
                 return  String.Equals (obj1, obj2, StringComparison.OrdinalIgnoreCase);
             }
         }

IEqualityComparer接口仍是很不錯的,不過如今基本上不這麼用了,而是直接提供了一個Lambda作爲比較函數;

【RouteData】

路由數據對象,它的大概意思我想你們應該知道了,上面提到過不少次,這裏就不介紹了;咱們直接看一下RouteData內部核心代碼段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public  RouteData (RouteBase route, IRouteHandler routeHandler)
{
     // arguments can be null.
     Route = route;
     RouteHandler = routeHandler;
 
     DataTokens = new  RouteValueDictionary ();
     Values = new  RouteValueDictionary ();
}
 
public  RouteValueDictionary DataTokens { get ; private  set ; }
 
public  RouteBase Route { get ; set ; }
 
public  IRouteHandler RouteHandler { get ; set ; }
 
public  RouteValueDictionary Values { get ; private  set ; }

經過構造函數咱們能瞭解到,保存了對Route對象的引用和IRouteHander接口的引用,爲何將IRouteHandler做爲構造函數參數,那是由於RouteBase根本沒有對IRouteHander接口的屬性定義;IRouteHandler接口在不在RouteBase或Route中不重要,由於Route能夠是自定義的,這裏的強制性是在RouteData中,它的構造函數必須接受IRouteHandler類型接口;

咱們接着看,在構造函數的下面兩行代碼中分別是實例化了DataTokens、Values兩個屬性,而類型是RouteValueDictionary,這也恰好和咱們上面分析的對上了;RouteValueDictionary是內部用來保存這些零散鍵值對數據容器,在Route、RouteData還有其餘地方均須要用到;就是由於RouteValueDictionary的Value是Object類型,因此能夠用來存聽任何類型的值,比較通用;

【RequestContext 】

RequestContext在上面也已經接觸不少次了,表示請求上下文,也就是跟當請求相關的全部數據都封裝在裏面;在後面的文章中,咱們將接觸不少相似Context的對象,如:ControlContext,ViewContext之類的,都是用來控制上下文的邊界,而不是直接傳遞零散的參數;

4.4】IRouteHandler 、IHttpHander兩個接口之間的關係

IRouteHandler接口是路由框架起做用的核心,只有提供了IRouteHandler實現才能順利的獲得背後的IHttpHandler接口;ASP.NETMVC提供了MvcRouteHandler對象來實現IRouteHandler接口,MvcRouteHandler在內部實例化實現了IHttpHandler接口的MvcHandler對象;MvcHandler而後經過RequestContext對象獲取RouteData對象,接着獲得相應的Control信息,進行後續的執行處理;

5.】UrlRoutingHandler 對象內部結構及擴展應用

在ASP.NETRouting路由框架中有一個很重要的IHttpHandler接口對象UrlRoutingHanlder,我想你確定很疑惑,爲何須要這樣一個對象;其實它的存在是爲了提供給咱們繞過UrlRoutingModule模塊的機會;根據上面的詳細的分析,咱們知道路由的入口在UrlRoutingModule,全部的路由相關的映射工做都在該類中完成,可是有時候咱們很想繞過UrlRoutingModule進行簡單的處理或者性能方面的優化考慮,這就派上用場了;我能想到的使用場景目前來看是對ASP.NET第版本的項目作Url重寫是比較方便,首先咱們的項目須要創建在低版本的ASP.NET之上,可是須要添加Url.ReWriter的功能,就須要咱們本身去實現這樣的功能;

可是工做量和性能都很難控制好,若是使用這裏提供的UrlRoutingHandler進行實現就很方便了,UrlRoutingHandler給咱們使用ASP.NETRouting框架的機會同時也不須要關心是否配置了UrlRoutingModule;

1
public  abstract  class  UrlRoutingHandler : IHttpHandler

根據代碼看出它是一個抽象類,直接實現IHttpHanlder接口,可是重要的是ProcessRequest方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected  virtual  void  ProcessRequest (HttpContextBase httpContext)
         {
             if  (httpContext == null )
                 throw  new  ArgumentNullException ( "httpContext" );
 
             var  rd = RouteCollection.GetRouteData (httpContext);
             if  (rd == null )
                 throw  new  HttpException ( "The incoming request does not match any route" );
             if  (rd.RouteHandler == null )
                 throw  new  InvalidOperationException ( "No  IRouteHandler is assigned to the selected route" );
 
             RequestContext rc = new  RequestContext (httpContext, rd);
 
             var  hh = rd.RouteHandler.GetHttpHandler (rc);
             VerifyAndProcessRequest (hh, httpContext);
         }
 
         protected  abstract  void  VerifyAndProcessRequest (IHttpHandler httpHandler, HttpContextBase httpContext);

該方法的邏輯跟UrlRoutingModule裏的PostResolveRequestCache方法是差很少的,都會經過全局RouteCollection集合進行匹配當前的RouteData對象;那就足夠說明這個過程不會再經過UrlRoutingModule模塊;方法的最後一行是執行一個模板方法:VerifyAndProcessRequest ,該方法是留給子類去實現的;

那麼這裏將路由和執行合在一塊兒了,基類負責路由子類負責執行,很不錯的設計方法;

總結:這篇文章基本上介紹了跟路由相關的核心對象,可是還有一些其餘輔助的類這裏並無進行講解,固然若是你有興趣能夠本身去看看;這篇文章是爲了讓咱們能對路由的處理流程及結構有個瞭解,作到能在適當的時候進行擴展和查找問題;

線程同步有關鎖的術語介紹

在多線程中,鎖是一種最經常使用的同步工具,下面詳細講講帶有鎖字的一些術語:

1.鎖的具體實現原理:

(1).互斥鎖(Mutex)

用一個「互斥鎖」的對象,任一時刻,只有一個線程能訪問這個對象,也就是把代碼分紅一個個臨界區域。在Linux下僞代碼以下:

複製代碼
pthread_mutex_t mutex;

pthread_mutex_init (&mutex, NULL); /*初始化鎖*/

pthread_mutex_lock(&mutex); /*獲取互斥鎖,也就是加鎖*/

... /*臨界區*/

pthread_mutex_unlock(&mutex); /*解鎖互斥鎖*/
複製代碼

如圖,中間的臨界區就實現了加鎖,每次只有一個線程才能訪問。基本上咱們線程同步用的都是互斥鎖。

2.自旋鎖(Spin Lock)

跟互斥鎖類型,都是爲了實現互斥訪問某個對象,可是互斥鎖在資源被佔用的時候會進入睡眠,而自旋鎖則會一直循環去探測可否獲取資源,在某種意義上,就是一直while循環探測。因此自旋鎖很容易就佔用cpu過多,可是不須要線程的休眠調度等,會效率比較高,適用加鎖時間很短的狀況。

3.讀寫鎖(RWLock)

讀寫鎖就是一個特殊的自旋鎖,只是把須要進入臨界區的訪問者分紅讀者和寫者,寫者是排他的,可是容許多個讀者同時存在。也就是說若是沒有讀者和寫者,那麼寫者能夠馬上得到讀寫鎖,不然它必須自旋在那裏,直到沒有任何寫者或讀者。若是讀寫鎖沒有寫者,即便有其餘讀者,這個讀者也能夠當即得到該讀寫鎖,不然讀者必須自旋在那裏,直到寫者釋放該讀寫鎖。

互斥鎖跟自旋鎖一些優缺點:

Spinlock優勢:沒有昂貴的系統調用,一直處於用戶態,執行速度快。

Spinlock缺點:一直佔用cpu,並且在執行過程當中還會鎖bus總線,鎖總線時其餘處理器不能使用總線。

Mutex優勢:不會忙等,得不到鎖會sleep。

Mutex缺點:sleep時會陷入到內核態,須要昂貴的系統調用。

2.鎖的一些分類

1.遞歸鎖(Recursive Lock)和非遞歸鎖(Non-Recursive Lock)

兩個惟一的區別就是一個線程能夠屢次獲取一個遞歸鎖,而不會致使死鎖,而屢次獲取一個非遞歸鎖就會致使死鎖。以下:

複製代碼
mutex_init(&mutex);
void fun()
{
  lock(&mutex);
  //do something1
  fun2();
  unlock&mutex);
}

void fun2()
{
  lock(&mutex);
  //do something2
  unlock(&mutex);
}
複製代碼

在fun()函數加鎖調用了fun2(),而fun2()也加了鎖,若是是非遞歸鎖,那麼fun獲取了mutex,fun2再去獲取mutex,就會致使死鎖了。

2.樂觀鎖(Optimistic Lock)和悲觀鎖(Pessimistic Lock)

主要是用於關係型數據庫存儲。樂觀鎖,大可能是基於數據版本(Version)記錄機制實現,即爲數據增長一個版本標識。讀取出數據時,將此版本號一同讀出,以後更新時,對此版本號加一。之後提。優勢是對於併發的數據庫讀取,避免了長時間的加鎖開銷等待,缺點也比較明顯,可能致使不正確的數據存入數據庫。悲觀鎖就比較容易理解了,也就是在整個數據庫操做中,數據都處於鎖定狀態。也就是說在數據進行一個讀的事務中,全部對整個數據的修改都無法進行。

3.死鎖(Dead Lock)和活鎖(Live Lock)

死鎖你們應該都比較清楚,簡單地說,就是進入死等待,例如P1佔用了資源A,請求資源B,而P2佔用了資源B,請求資源A,這樣就致使雙方一直在等待。而活鎖就是資源一直輪不到本身使用,致使一直飢餓,例如若是事務T1封鎖了數據R,事務T2請求封鎖R,因而T2等待。T3也請求封鎖R,當T1釋放了R上的封鎖以後系統首先批准了T3的請求,T2仍然等待。而後T4又請求封鎖R,當T3釋放了R上的封鎖以後系統又批准了T4的請求,...,T2有可能永遠等待,這就是活鎖的情形。

主要是一些概念的介紹,具體的還須要具體去用了才能體會。

謝謝指教。

分類:  Coding
標籤:  Lock
相關文章
相關標籤/搜索