文章内容

继续上一章节的内容,通过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 requestif (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 > 0) {app = (HttpApplication)_freeList.Pop(); _numFreeAppInstances--;if (_numFreeAppInstances < _minFreeAppInstances) { _minFreeAppInstances = _numFreeAppInstances;} }}if (app == null) { // If ran out of instances, create a new oneapp = (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 initializationcontext.ConfigurationPath = context.Request.ApplicationPathObject; // keep HttpContext.Current working while running user codeusing (new DisposableHttpContextWrapper(context)) { // Build module list from configif (HttpRuntime.UseIntegratedPipeline) {Debug.Assert(_moduleConfigInfo != null, "_moduleConfigInfo != null");Debug.Assert(_moduleConfigInfo.Count >= 0, "_moduleConfigInfo.Count >= 0"); try {context.HideRequestResponse = true; _hideRequestResponse = true; InitIntegratedModules();}finally { context.HideRequestResponse = false;_hideRequestResponse = false; } }else { InitModules();// this is used exclusively for integrated modeDebug.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 pathcontext.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之前的那点事儿系列(2):HttpRuntime详解分析(上)

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

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

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

  3. 不干正事儿系列文章1:Sonic Pi简单应用

    文章目录 Sonic Pi简单应用 0. Intro 1. Sonic Pi简单介绍 1.1 安装 1.2 案例 2. Sonic Pi和随机数 2.1 和弦的生成 2.2 旋律的生成 2.3 歌曲中 ...

  4. linux 那些事儿系列

    fudan_adc的博客主要博文包括: linux那些事儿系列 : http://blog.csdn.net/fudan_abc/article/category/335670 linux内核修炼之道 ...

  5. MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决

    MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 一.简介 MySQL是最流行的开放源码SQL数据库管理系统,它是由MySQL AB公司开发.发布并支持的.有以下特点: MySQL是 ...

  6. 【Dubbo源码阅读系列】之远程服务调用(上)

    今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...

  7. 轻松上云系列之一:本地数据迁移上云

    本文档围绕如何将您的本地数据迁移到阿里云,提供了多个场景的实践方案. 背景信息 在云计算服务高速发展的今天,如何方便快捷地将已有的服务器系统迁移上云,有着非常重要的意义.阿里云服务器迁移服务方案,即迁 ...

  8. Python语言学习:创建/删除文件/文件夹、获取当前文件/文件夹路径(系统环境路径/目录)、获取当前文件夹下的所有子文件路径等代码(os系列用法)实现之详细攻略

    Python语言学习:创建/删除文件/文件夹.获取当前文件/文件夹路径(系统环境路径/目录).获取当前文件夹下的所有子文件路径等代码(os系列用法)实现之详细攻略 目录 系统环境路径的设置 1.sys ...

  9. Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例

    转载自  Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例 第1部分 ArrayList介绍 ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与 ...

最新文章

  1. python描边_【基础】学习笔记52-Python3 matplotlib绘图-热力图1
  2. 【爬坑】在 IDEA 中运行 Hadoop 程序 报 winutils.exe 不存在错误解决方案
  3. ​HealthKit开发快速入门教程大学霸内部教程
  4. 量子计算机个人化时间,科学家发现量子算法可以停止时间
  5. 网站SEO优化如何才能避免被搜索引擎惩罚?
  6. 超图数据集管理基本操作和添加删除属性表字段
  7. datalist 分页
  8. 【例题+习题】【数值计算方法复习】【湘潭大学】(七)
  9. 在Myeclipse中配置 jboss 图解
  10. 201671010460朱艺璇 实验三作业互评与改进报告
  11. SqlServer标识列、修改标识列值
  12. Python连连看小游戏源代码
  13. 两张MD5值一样但实际不一样的图片
  14. 以“掌上东航”为例,论混合开发在企业级项目中的实践
  15. 机器人视觉分拣设计流程
  16. Graph Neural Network-Based Anomaly Detection in Multivariate Time Series 代码配置及解析
  17. KVM虚拟化技术的-NUMA技术和应用
  18. 计算机系统配置低会带来,低配电脑装什么系统?电脑配置低重装什么系统好
  19. 基于JavaSwing坦克大战游戏的设计和实现
  20. 爬虫案例——中超联赛新闻

热门文章

  1. Vue-使用webpack+vue-cli搭建项目
  2. Flask--WebSocket
  3. 本地存储cookie和localStorage区别特点
  4. 字符串的拆分以及分隔符所在不同位置的删除
  5. TCP为什么要三次握手和四次挥手
  6. Unity3D在C#编程中的一些命名空间的引用及说明
  7. Swift傻傻分不清楚系列(九)闭包
  8. 数据库系统原理(第6章:数据库安全与保护)
  9. Docker 图形界面管理工具 -- Portainer
  10. Thinking in Java 源代码 source code 在IDEA上运行