首页 > 代码库 > 并发请求时,HttpApplication的事件是如何执行的?
并发请求时,HttpApplication的事件是如何执行的?
1 疑问:
如果系统里注册了一个HttpModule,在BeginRequest里编写了代码,执行时如果卡住,会影响其他请求的执行吗?
查阅MSDN的解释:
http://msdn.microsoft.com/zh-cn/library/system.web.httpapplication(VS.80).aspx
HttpApplication 类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。HttpApplication 类的一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。
根据这里的描述不能回答如果有2个Request 同时进来怎么办?先执行Request1的第一个事件BeginRequest ,完成后处理Request2的第一个事件BeginRequest ?如果处理Request2的BeginRequest事件卡住了,其他Request还能不能继续往下执行?
2 一个请求执行的大体流程
ASP.net 执行请求的第一步是HttpRumtime.ProcessRequest方法,然后内部会到底HttpApplication的实例,然后执行HttpApplication. ProcessRequest的方法,最后调用HttpHandler的ProcessRequest方法。
反射看下源代码,HttpRuntime的核心函数:
HttpApplication的BeginProcessRequest函数
ResumeSteps函数:
_execSteps的数组的数据何时添加进去的呢?是在HttpApplication初始化的时候:
先看在哪里把当前的HttpApplication放入freeList中,定位到ResumeSteps函数的最末尾:
内部还写了个小逻辑,不保留超过100个HttpApplication的实例。
接着我们看函数 InitInternal,看我们的_execStep数组是怎么初始化的 :
在每个Module里都会对传进来的实例进行事件注册。比如:
接下来就把各个事件对应的委托都编入Steps里:
查看CreateEventExecutionSteps函数:
在调试的时候是可以看到编好的Steps里有哪些:
3总结下:总体流程图如下:
- HttpRumtime.ProcessRequest被调用
- 获得HttpApplication的实例
- 从空闲列表中取实例或产生新HttpApplication的实例
- 调用InitInternal方法初始化
- 调用InitModule来初始化
- 得到各个HttpModule
- 调用HttpModule的Init方法
- 各个HttpModule在init方法里定义事件对应的委托
- 将系统内置的处理步骤编入_execSteps中
- 将各个事件的对应的委托编入_execSteps中
- 调用HttpApplication.BeginProcessRequest
- 调用ResumeStep方法
- 逐个执行_exeSteps数组里的步骤
- 执行完后,回收此实例
4 回到我的疑问:
同时有2个Request 进来,系统会产生2个HttpApplication的实例,每个实例处理一个,2者之间不会相互影响。
再看MSDN的原话:
HttpApplication 类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。HttpApplication 类的一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。
应用程序按照以下顺序执行由 global.asax 文件中定义的模块或用户代码处理的事件:
什么叫被用于处理多个请求?
就是这个实例会回收,处理完这个请求后,可以再处理其他请求。
什么叫一次只能处理一个请求?如果有多个请求呢?
多个请求就产生多个实例呗!
怎么控制事件的执行顺序?
内部编一个Step的列表,按固定的顺序添加进去,然后顺序的执行一遍呀。
看来我有这个疑问的关键在于受了Application的实例只有1个的影响,所以看了MSDN的这句话,半天也没理解一下子说处理多个请求,一下又说处理一个请求,看了源代码,终于明白他为什么一下子写可以处理多个请求,一下又写只能处理1个请求。对,一个Web应用程序只有1个Application实例,但是那是指HttpApplication上的Application属性,不是指HttpApplication的实例只有1个,同时并发请求有多少个,就有多少个HttpApplication的实例。
5 调试证明HttpApplication实例是会产生多个,也能被重用:
编写一个HttpModule,代码如下:
public class HttpModule1 : IHttpModule{ public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); } void context_BeginRequest(object sender, EventArgs e) { if (((HttpApplication)sender).Request.RawUrl.EndsWith("Default.aspx")) { Thread.Sleep(20000); } }}
把它配置到Web.Config 中去:
<httpModules> <add name="HttpModule1" type="HttpModule1"/> </httpModules>
简单添加2个ASPX文件:Default.aspx 和 Test.aspx。然后启动调试:
1)请求Default.aspx
第一个Default.aspx请求到来,实例是971734,让它继续执行,卡住 。
2)再开一个浏览器,请求Test.aspx
第二个Test.aspx请求到来,实例是45150396,与之前的并不一致,说明有并发请求到来时,有多个HttpApplication的实例。
3)过了20秒后,再请求Test.aspx:
实例又变回971734 ,说明之前执行Default.aspx的实例没有销毁,这里又重用了。
并发请求时,HttpApplication的事件是如何执行的?