MVC之前的那点事儿系列(4):Http Pipeline详细分析(上)

文章内容

继续上一章节的内容,通过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之前的那点事儿系列文章,包括了原创,翻译,转载等各类型的文章,如果对你有用,请推荐支持一把,给大叔写作的动力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/264801.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java开发人员的十大戒律

对Java开发者来说&#xff0c;有许多的标准和最佳实践。本文列举了每一个开发人员必须遵从的十大基本法则&#xff1b;如果有了可以遵从的规则而不遵从&#xff0c;那么将导致的是十分悲惨的结局。1&#xff0e; 在你的代码里加入注释每个人都知道这点&#xff0c;但不知何故…

c++学习书籍推荐《Advanced C++》下载

百度云及其他网盘下载地址&#xff1a;点我 作者简介 James Coplien先在威斯康星大学获得电气与计算机工程学士学位&#xff0c;后又在该大学获得计算机科学硕士学位。他在贝尔实验室的软件产品研发部门工作&#xff0c;在这个部门从一开始就使用C程序设计语言。近年来致力于大…

Centos 编译安装nodejsexpress框架

一. 下载nodejs 版本 wget http://nodejs.org/dist/v0.10.28/node-v0.10.28.tar.gz 二. 编译安装 cp node-v0.10.28.tar.gz /usr/src/ cd /usr/src tar zxvf node-v0.10.28.tar.gz cd node-v0.10.28/ ./configuration --prefix/usr/local/node make&make install 设置环境变…

Spring Boot 2 实践记录之 条件装配

实验项目是想要使用多种数据库访问方式&#xff0c;比如 JPA 和 MyBatis。 项目的 Service 层业务逻辑相同&#xff0c;只是具体实现代码不同&#xff0c;自然是一组接口&#xff0c;两组实现类的架构比较合理。 不过这种模式却有一个问题&#xff0c;如果 Bean 是按实现类装配…

通过简易的前台代码实现无限二级域名转向(来自无忧 biyuan老矣)

只要空间支持泛域名解析&#xff0c;无须服务端脚本语言和DNS&#xff0c;通过前台代码便可实现无限二级域名的构造&#xff1a; <html> <head> <title>碧原网络免费二级域名</title> <head> </head> <body> <scrīp…

MySQL入门-3:安装与客户端工具

大纲1、安装 MySQL2、检索数据3、数据过滤一、安装环境CentOS-6.5-i386mysql 5.1.73为了方便&#xff0c;这里采用yum方式安装&#xff0c;对于学习实验环境完全没问题&#xff0c;注意下面的操作都以root身份操作。除非对MySQL需要定制化或者安装多个实例&#xff0c;建议使用…

实验吧-web-天下武功唯快不破(Python中byte和str的转换)

题目&#xff1a;看看响应头 打开网站&#xff0c;既然已经提示我们看响应头了&#xff0c;那我们就看看呗(习惯bp&#xff0c;也可直接F12查看) 可以看到&#xff0c;响应头部分有个FLAG&#xff0c;而且有提示&#xff1a;please post what you find with parameter:key 所以…

一个弹出页面的徐徐升起的js效果

<HTML><HEAD><title>提醒信息</title><base target"_blank"><SCRIPT language"JavaScript"> window.resizeTo(220,210); var windowW220 // wide var windowH210 // high var Yoffset0 // in pixels, ne…

我国域名***日均58起 高安全DNS防御系统建设刻不容缓

日前&#xff0c;国家互联网应急中心发布的《2013年中国互联网网络安全报告》显示&#xff0c;作为互联网运行的关键基础设施&#xff0c;我国域名系统面临安全漏洞和拒绝服务***等多种威胁&#xff0c;是影响网络稳定运行的薄弱环节。中心监测报告显示&#xff0c;2013年针对我…

P4592 [TJOI2018]异或 (可持久化Trie)

[题目链接] https://www.luogu.org/problemnew/show/P4592 题目描述 现在有一颗以\(1\)为根节点的由\(n\)个节点组成的树&#xff0c;树上每个节点上都有一个权值\(v_i\)。现在有\(Q\)次操作&#xff0c;操作如下&#xff1a; \(1\;x\;y&#xff1a;\)查询节点xx的子树中与\(y\…

xml与数据库略解

1.0 简介 本论文简要的探讨了XML和数据库之间的关系&#xff0c;同时列出一些可以使用数据库处理XML文档的软件。虽然这里不打算详尽地介绍这些软件&#xff0c;但是笔者希望它能够描述使用数据库处理XML文档中的主要部分。这里有点偏向与关系数据库&#xff0c;…

魔方阵

①问题描述 魔方阵是一个古老的智力问题&#xff0c;它要求在一个mm的矩阵中填入1&#xff5e;m2的数字&#xff08;m为奇数&#xff09;&#xff0c;使得每一行、每一列、每条对角线的累加和都相等&#xff0c;如图1所示。 15 8 1 24 17 16 14 7 5 23 22 20 13 6…

专题训练5总结

这个专题学习了两种算法 1.稳定婚姻匹配问题 2.最大团问题 稳定婚姻匹配问题&#xff1a; 1.Stable Match 关于信号站匹配 多了一个容量的权值 如果距离相同看容量大小 数据处理较麻烦&#xff01; 2.marriage 稳定婚姻匹配问题入门题 3.The Stable Marriage problem 和入门题…

CodeSmith实用技巧(八):生成的代码输出到文件中

在CodeSmith中&#xff0c;要把生成的代码文件输出到文件中&#xff0c;你需要在自己的模版中继承OutputFileCodeTemplate类。<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" /><% CodeTemplate Language"C#"TargetL…

python 3的33个保留字列表_python 33个保留字是什么意思

and 用于表达式运算&#xff0c;逻辑与操作as 用于类型转换assert 断言&#xff0c;用于判断变量或条件表达式的值是否为真break 中断循环语句的执行class 用于定义类continue 继续执行下一次循环def 用于定义函数或方法del 删除变量或者序列的值elif 条件语句 与if else 结合使…

SSH整合jar包下载

2019独角兽企业重金招聘Python工程师标准>>> http://blog.sina.com.cn/s/blog_8a3d83320100zhmp.html svn使用 spring 下载 http://maven.springframework.org/release/org/springframework/spring/4.0.5.RELEASE/ http://repo.spring.io/libs-release-local/org/sp…

面试之什么是java虚拟机

java虚拟机体系结构 方法区 堆 java虚拟机栈 本地方法栈方法区 java虚拟机编译的class文件中二进制数据类型解析数据存在方法区中 是所有线程共享和存在数据的线程安全问题 当二个线程使用同一类并且类还被加载 则让一个线程加载 另一个线程等待java虚拟机栈 是线程私有的 既决…

高质量c/c++编程(9)

第9章 类的构造函数、析构函数与赋值函数构造函数、析构函数与赋值函数是每个类最基本的函数。它们太普通以致让人容易麻痹大意&#xff0c;其实这些貌似简单的函数就象没有顶盖的下水道那样危险。每个类只有一个析构函数和一个赋值函数&#xff0c;但可以有多个构造函数&#…

三合一剪弦器怎么用_三合一冲锋衣推荐选购攻略:

一、冲锋衣的类别二、三合一冲锋衣小评测。三、冲锋衣维护一、冲锋衣的类别冲锋衣分&#xff1a;硬壳、软壳&#xff0c;三合一&#xff0c;三种类型。软壳是介于抓绒衣和冲锋衣之间的衣服&#xff0c;防水上比硬壳差&#xff0c;只能防小雨&#xff0c;但优势在于活动方便&…

Celery 之异步任务、定时任务、周期任务

什么是Celery?Celery 是芹菜Celery 是基于Python实现的模块, 用于执行异步定时周期任务的其结构的组成是由 1.用户任务 app 2.管道 broker 用于存储任务 官方推荐 redis rabbitMQ / backend 用于存储任务执行结果的 3.员工 worker 一 异步任务 1 from celery import…