文章内容

继续上一章节的内容,通过HttpApplicationFactory的GetApplicationInstance静态方法获取实例,然后执行该实例的BeginProcessRequest方法进行执行余下的Http Pipeline 操作,代码如下:

// Get application instance
IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);

那GetApplicationInstance这个方法究竟做了啥呢?难道只是new一个新对象出来?感觉应该不像,那我们就来看看HttpApplicationFactory类的GetApplicationInstance静态方法源码:

internal static IHttpHandler GetApplicationInstance(HttpContext context) {
if (_customApplication != null)
return _customApplication; // Check to see if it's a debug auto-attach request
if (context.Request.IsDebuggingRequest)
return new HttpDebugHandler(); _theApplicationFactory.EnsureInited(); _theApplicationFactory.EnsureAppStartCalled(context); return _theApplicationFactory.GetNormalApplicationInstance(context);
}

里面有3行代码我已经标记为粗体了,在解释每行代码的具体作用之前,先看看_theApplicationFactory对象实例从哪里来,通过查看该字段的声明代码可以看到它是单例的实现。

// the only instance of application factory
private static HttpApplicationFactory _theApplicationFactory = new HttpApplicationFactory();

第一行粗体代码是执行,该实例的EnsureInited方法,这个方法会通过lock的方式调用Init方法(好处自然不用多说了吧),代码如下:

private void EnsureInited() {
if (!_inited) {
lock (this) {
if (!_inited) {
Init();
_inited = true;
}
}
}
}

通过查找 Init方法的代码以及其中2行如下代码里的细节,我们可以得知,这2行代码主要是从global.asax获取内容,然后进行编译。

_appFilename = GetApplicationFile();
CompileApplication();

所以,HttpApplicationFactory._theApplicationFactory.EnsureInited()  的方法首先检查HttpApplicationFactory是否被初始化,如果没有,就通过HttpApplicationFactory.Init()进行初始化。在Init()中,先获取global.asax文件的完整路径,然后调用CompileApplication()对global.asax进行编译。

第2行粗体的EnsureAppStartCalled方法,最终会调用如下的私有方法FireApplicationOnStart,代码如下:

private void FireApplicationOnStart(HttpContext context) {
if (_onStartMethod != null) {
HttpApplication app = GetSpecialApplicationInstance(); app.ProcessSpecialRequest(
context,
_onStartMethod,
_onStartParamCount,
this,
EventArgs.Empty,
null); RecycleSpecialApplicationInstance(app);
}
}

通过代码我们能够得知HttpApplicationFactory._theApplicationFactory.EnsureAppStartCalled(context)  创建特定的HttpApplication实例,触发ApplicationOnStart事件,执行ASP.global_asax中的Application_Start(object sender, EventArgs e)方法。然后在处理完事件以后就立即被回收掉,因为系统初始化只需要一次,但是其中的GetSpecialApplicationInstance里会对IIS7做一些特殊的事情,我们后面的章节会讲到。

第3行的粗体代码是我们这里要说的重点,它方法里的代码如下:

private HttpApplication GetNormalApplicationInstance(HttpContext context) {
HttpApplication app = null; lock (_freeList) {
if (_numFreeAppInstances > ) {
app = (HttpApplication)_freeList.Pop();
_numFreeAppInstances--; if (_numFreeAppInstances < _minFreeAppInstances) {
_minFreeAppInstances = _numFreeAppInstances;
}
}
} if (app == null) {
// If ran out of instances, create a new one
app = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType); using (new ApplicationImpersonationContext()) {
app.InitInternal(context, _state, _eventHandlerMethods);
}
} return app;
}

如果在有空闲的HttpApplication实例,就直接用,如果没有就新创建,然后调用InitInternal方法进行初始化相关的内容,最后返回该HttpApplication实例。

让我们来看看HttpApplication的核心方法InitInternal里都是干了什么事儿吧,先上代码,有点多,但是很值得:

internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
Debug.Assert(context != null, "context != null"); // Remember state
_state = state; PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES); try {
try {
// Remember context for config lookups
_initContext = context;
_initContext.ApplicationInstance = this; // Set config path to be application path for the application initialization
context.ConfigurationPath = context.Request.ApplicationPathObject; // keep HttpContext.Current working while running user code
using (new DisposableHttpContextWrapper(context)) { // Build module list from config
if (HttpRuntime.UseIntegratedPipeline) { Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");
Debug.Assert(_moduleConfigInfo.Count >= , "_moduleConfigInfo.Count >= 0"); try {
context.HideRequestResponse = true;
_hideRequestResponse = true;
InitIntegratedModules();
}
finally {
context.HideRequestResponse = false;
_hideRequestResponse = false;
}
}
else {
InitModules(); // this is used exclusively for integrated mode
Debug.Assert(null == _moduleContainers, "null == _moduleContainers");
} // Hookup event handlers via reflection
if (handlers != null)
HookupEventHandlersForApplicationAndModules(handlers); // Initialization of the derived class
_context = context;
if (HttpRuntime.UseIntegratedPipeline && _context != null) {
_context.HideRequestResponse = true;
}
_hideRequestResponse = true; try {
Init();
}
catch (Exception e) {
RecordError(e);
}
} if (HttpRuntime.UseIntegratedPipeline && _context != null) {
_context.HideRequestResponse = false;
}
_hideRequestResponse = false;
_context = null;
_resumeStepsWaitCallback= new WaitCallback(this.ResumeStepsWaitCallback); // Construct the execution steps array
if (HttpRuntime.UseIntegratedPipeline) {
_stepManager = new PipelineStepManager(this);
}
else {
_stepManager = new ApplicationStepManager(this
);
} _stepManager.BuildSteps(_resumeStepsWaitCallback);

}
finally {
_initInternalCompleted = true; // Reset config path
context.ConfigurationPath = null; // don't hold on to the context
_initContext.ApplicationInstance = null;
_initContext = null;
}
}
catch { // Protect against exception filters
throw;
}
}

该代码主要有2个功能,一个是初始化大家熟悉的HttpModules,一个是通过BuildSteps执行20多个生命周期事件的处理函数(这部分内容,我们将在下一章节详细讲解Http Pipeline)。通过上面的代码我们可以看出,每个功能都有一个特殊判断,判断IIS是否是IIS7的集成模式,如果是就有特殊的步骤,如果不是就走一般的步骤,两者直接的差异分别是:IIS7初始化HttpModules的时候会从网站配置的Modules里读取(因为IIS7预加载CLR和大批量Modules),BuildSteps的时候, IIS7集成模式走的是自己特殊的流程(加载服务器上的HttpModules)。

让我们先总结一下再看代码,InitInternal方法的主要功能如下:

  1. InitModules():根据Web.Config的设置,加载相应的HttpModules。
  2. InitIntegratedModules():会加载IIS7集成模式下在服务器上设定的HttpModuels和Web.config里system.webserver下的HttpModuels。
  3. HookupEventHandlersForAppplicationAndModules:根据发生的事件,调用HttpApplication实例中相应的事件处理函数。
  4. 创建很多实现IExecutionStep接口的类的实例并添加到当前HttpApplication实例的_execSteps中,等待回调时执行。从这里我们可以看到HttpApplication是以异步的方式处理请求, 对请求的很多处理工作都放入了_execStep等待回调时执行。

至此,除了20多个周期事件和Handler相关的代码我们没有讲解,其它和HttpApplication相关的并且对我们有帮助的,已经差不多清晰了。关于20多个周期事件和执行Handler方面的内容,我们下一章节再做详细解释。

参考资料:

http://msdn.microsoft.com/en-us/magazine/cc188942.aspx

http://msdn.microsoft.com/en-us/library/bb470252.aspx

http://www.cnblogs.com/zhaoyang/archive/2011/11/16/2251200.html

同步与推荐

本文已同步至目录索引:MVC之前的那点事儿系列

MVC之前的那点事儿系列文章,包括了原创,翻译,转载等各类型的文章,如果对你有用,请推荐支持一把,给大叔写作的动力。

MVC之前的那点事儿系列(4):Http Pipeline详细分析(上)的更多相关文章

  1. MVC之前的那点事儿系列(10):MVC为什么不再需要注册通配符(*.*)了?

    文章内容 很多教程里都提到了,在部署MVC程序的时候要配置通配符映射(或者是*.mvc)到aspnet_ISPAI.dll上,在.NET4.0之前确实应该这么多,但是.NET4.0之后已经不要再费事了 ...

  2. MVC之前的那点事儿系列(8):UrlRouting的理解

    文章内容 根据对Http Runtime和Http Pipeline的分析,我们知道一个ASP.NET应用程序可以有多个HttpModuel,但是只能有一个HttpHandler,并且通过这个Http ...

  3. MVC之前的那点事儿系列(6):动态注册HttpModule

    文章内容 通过前面的章节,我们知道HttpApplication在初始化的时候会初始化所有配置文件里注册的HttpModules,那么有一个疑问,能否初始化之前动态加载HttpModule,而不是只从 ...

  4. MVC之前的那点事儿系列(9):MVC如何在Pipeline中接管请求的?

    文章内容 上个章节我们讲到了,可以在HttpModules初始化之前动态添加Route的方式来自定义自己的HttpHandler,最终接管请求的,那MVC是这么实现的么?本章节我们就来分析一下相关的M ...

  5. MVC之前的那点事儿系列(7):WebActivator的实现原理详解

    文章内容 上篇文章,我们分析如何动态注册HttpModule的实现,本篇我们来分析一下通过上篇代码原理实现的WebActivator类库,WebActivator提供了3种功能,允许我们分别在Http ...

  6. MVC之前的那点事儿系列(5):Http Pipeline详细分析(下)

    文章内容 接上面的章节,我们这篇要讲解的是Pipeline是执行的各种事件,我们知道,在自定义的HttpModule的Init方法里,我们可以添加自己的事件,比如如下代码: public class ...

  7. MVC之前的那点事儿系列(3):HttpRuntime详解分析(下)

    文章内容 话说,经过各种各样复杂的我们不知道的内部处理,非托管代码正式开始调用ISPAIRuntime的ProcessRequest方法了(ISPAIRuntime继承了IISPAIRuntime接口 ...

  8. MVC之前的那点事儿系列(2):HttpRuntime详解分析(上)

    文章内容 从上章文章都知道,asp.net是运行在HttpRuntime里的,但是从CLR如何进入HttpRuntime的,可能大家都不太清晰.本章节就是通过深入分析.Net4的源码来展示其中的重要步 ...

  9. MVC之前的那点事儿系列(1):进入CLR

    MVC之前的那点事儿系列,是笔者在2012年初阅读MVC3源码的时候整理的,主要讲述的是从HTTP请求道进入MVCHandler之前的内容,包括了原创,翻译,转载,整理等各类型文章,当然也参考了博客园 ...

随机推荐

  1. weinre使用

    2016-1-21 更新说明: 微信web开发者工具已经集成了weinre,只需设置手机代理便可调试任意页面,更简单更方便,推荐使用! Web应用开发者需要针对手机进行界面的调试,但是手机上并没有称心 ...

  2. Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic

    Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic 1.1. ThreadLocal 设计模式1 1.2. ...

  3. Atitit 图像处理 常用8大滤镜效果 Jhlabs 图像处理类库 java常用图像处理类库

    Atitit 图像处理 常用8大滤镜效果 Jhlabs 图像处理类库 java常用图像处理类库1.1. 5种常用的Photoshop滤镜,分别针对照片的曝光.风格色调.黑白照片处理.锐利度.降噪这五大 ...

  4. C#学习系列-类与结构的区别

    参考:http://www.microsoftvirtualacademy.com/Content/ViewContent.aspx?et=9851&m=9830&ct=31038 如 ...

  5. 用Chrome插件对自动化测试TestWriter进行录制

    1.打开Chrome浏览器,在浏览地址中输入: chrome://extensions/,并勾选开发者模式.如图: 2.点击按钮[加载已解压的扩展程序-].如图: 3.选择Testwriter客户端下 ...

  6. Jquery的基本架构

    引入  以前学习原生JS然后切换到用JQ的时候总觉得很不习惯,甚至有点排斥用JQ.后来自己写项目一直到公司实习用JQ的这段时间,才深深感受到JQ的强大~JQ不仅做到兼容很多浏览器,还能很方便地使用JS ...

  7. C++标准库vector类型详解

    Vector简介 vector是定义在C++标准模板库,它是一个多功能.能够操作多种数据结构和算法的模板类(关于模板类我们后面会介绍,如何创建自己的模板类).vector是一个容器,能够像容器一样存放 ...

  8. 找到SQL Server数据库历史增长信息

        很多时候,在我们规划SQL Server数据库的空间,或向存储方面要空间时,都需要估算所需申请数据库空间的大小,估计未来最简单的办法就是看过去的趋势,这通常也是最合理的方式.     通常来讲 ...

  9. 后端码农谈前端(CSS篇)第三课:选择器

    一.选择器 1.ID选择器: 语法:首先,ID 选择器前面有一个 # 号 - 也称为棋盘号或井号.请看下面的规则: *#intro {font-weight:bold;} 与类选择器一样,ID 选择器 ...

  10. nodejs+phantomjs+七牛 实现截屏操作并上传七牛存储

    近来研究了下phantomjs,只是初涉,还谈不上深入研究,首先介绍下什么是phantomjs. 官网上的介绍是:”PhantomJS is a headless WebKit scriptable ...