"Application 这是Web应用程序生命期中的全局保存区,保存在Application中的数据是全局有效的;在Asp.Net中,有一个应用程序池,其中保存了数个(或数十个)应用程序实例,每一次请求都会从池中取一个实例来处理请求"
这个结论是错误的,对于web应用程序来说,一个web应用程序有且只有一个HttpApplicationState对象,这个对象是在第一个用户第一次访问该web应用程序的任意url时由asp.net框架创建的,而且这个实例是唯一的,是客户不可创建的,所以你的所谓的关于Application的论断是错误的,请在贴子之前考虑清楚,这里有许多初学者,不要误导了他们!具体细节请参照MSDN.
这个结论是错误的,对于web应用程序来说,一个web应用程序有且只有一个HttpApplicationState对象,这个对象是在第一个用户第一次访问该web应用程序的任意url时由asp.net框架创建的,而且这个实例是唯一的,是客户不可创建的,所以你的所谓的关于Application的论断是错误的,请在贴子之前考虑清楚,这里有许多初学者,不要误导了他们!具体细节请参照MSDN.
"在Asp.Net中,有一个应用程序池,其中保存了数个(或数十个)应用程序实例,每一次请求都会从池中取一个实例来处理请求"你可能有些误会了,可能是我说的不明白,我没有说HttpApplicationState有多个实例,而是HttpApplication,也就是Global.asax定义的应用程序的对象,而不是保存数据的HttpContext的Application属性;对应HttpContext的属性,应该是ApplicationInstance我是深入研究了MSDN和Asp.Net的源代码才这样说的,实际上你可以想想,如果只有一个实例来处理请求,那么这个对象会面临很复杂的线程访问的处理,因为对服务器来说,同一个时间里面会有很多请求同时产生,如果只使用一个Application实例来处理请求,那么会造成很严重的堵塞;实际上,Asp.Net内部会有一个ApplicationFactory的类,有这个类来维护应用程序池,针对每一个请求来获取一个实例处理它。
这一段话是从MSDN中摘录下来的:
“此类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。”
ms-help://MS.VSCC/MS.MSDNVS.2052/cpref/html/frlrfsystemwebhttpapplicationclasstopic.htm对于HttpApplicationState,的确只有一个实例,它是HttpApplicationFactory类的一个属性,针对整个应用程序是唯一的;我是没有说清楚这二者的差异,谢谢你的提醒。
HttpContext.ApplicationInstace -> HttpApplication这样的命名的确很不容易区分
:)
另外,你说的只有一个对象会造成多线程同步复杂,我不明白,会复杂在哪里?我不知道你的这些资料是从哪里的来的,如果你像确切的了解asp.net对象中具体包括了那些对象,办法有一个,就是在内存窗口中观察。
“此类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。”
这句话恰恰说明你的观点是不正确的,你的观点是同时能处理多个请求,可上面的话却说一次只能处理一个,不知是我没弄懂你的意思,还是你根本就没领会上面的话的意思?
你后面谈到呢基本正确,希望你能掌握足够的证据之后在给下定义。
"如果你像确切的了解asp.net对象中具体包括了那些对象,办法有一个,就是在内存窗口中观察"
你知道IL吗?知道怎么反编译吗?
ApplicationFactory这个类在MSDN中是找不到的,只能通过反编译之后查看源代码,我是看过之后再结合MSN才得出结论,我可以告诉你,我不会无根据的说这些结论,我的结论都是基于事实的,建议你反编译查看Asp.Net的源代码再来讨论。"另外,你说的只有一个对象会造成多线程同步复杂,我不明白,会复杂在哪里?"
如果你弄不懂这句话我也没办法,实际上一个请求进来之后,ApplicationFactory会从池中获取一个应用程序实例来处理该请求,再请求结束之前,这个实例不能再处理其他请求,如果允许处理其他请求,那么就会面临实例字段的多线程处理,如果进行大量的Lock操作会降低效率,而且必须要维护不同线程的状态,所以Asp.Net的做法不是Lock某个实例字段,而是Lock整个实例。“此类的实例是在 ASP.NET 基础结构中创建的,而不是由用户直接创建的。一个实例在其生存期内被用于处理多个请求,但它一次只能处理一个请求。这样,成员变量才可用于存储针对每个请求的数据。” -MSDN
“在Asp.Net里面,Web应用程序的对象的类是HttpApplication,在一次请求中,可以通过HttpContext.ApplcationInstance来获得应用程序的实例,这个实例是存在于应用程序池的,在应用程序生存期始终会留在池里,它可能会处理很多请求,但是一次只能处理一个,从请求开始到请求结束都不能替换。" -我说的上面这两段话这两段话难道表达的不是一个意思?
“你的观点是同时能处理多个请求” 我不知道你的结论是怎么得来的,希望你看清楚我的回复在说。
{
HttpApplication app; //这次要返回的应用程序实例
Stack appStack; app = null;
lock (this._freeList) //因为_freeList是实例字段,所以需要Lock保证线程同步
if (this._numFreeAppInstances > 0) // 如果空闲实例数量大于0
{
app = (HttpApplication) this._freeList.Pop();//从空闲实例的堆栈中获取一个实例
this._numFreeAppInstances = this._numFreeAppInstances - 1;//空闲实例计数器递减
}
if (app == null) //如果没有获取到
{
app = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);//动态创建一个实例,HttpRuntime.CreateNonPublicInstance实际上会调用Activator.CreaateInstance,_theApplicationType就是Global.asax中的类型
app.InitInternal(context, this._state, this._eventHandlerMethods); //初始化该实例
}
return app;
}这就是证据
这是事实,的确,这样会面临同步的问题,所以MSDN中建议Global中不要使用实例字段,尽量使用静态字段,因为使用实例字段的话,那么两次请求之间可能会面临不同的应用程序实例,也许它们的某个实例字段的值不一样:
"Init 方法与 Application_OnStart 事件不同,因为总是对应用程序中的所有 HttpApplication 实例调用该方法。在应用程序的生存期中只调用一次 Application_OnStart,这便是对 HttpApplication 的第一个实例调用。使用 Application_OnStart 只是为了创建或修改所有管线实例共享的状态,例如 ApplicationState 对象的使用。因为局部变量不被多个 HttpApplication 实例共享,所以不要使用它来创建局部变量。紧接着销毁 HttpApplication 类的实例之前调用 HttpApplication.Dispose 方法。您可以使用它来清理任何本地资源。Dispose 方法与 Application_OnEnd 事件不同,因为总是对应用程序中所有 HttpApplication 实例调用该方法。在应用程序的生存期中只引发一次 Application_OnEnd,这便是对被强行停止 HttpApplication 的最后一个实例引发。使用 Application_OnEnd 只是为了清理所有管线实例共享的状态或资源,例如 ApplicationState 对象的使用。因为局部变量不被多个 HttpApplication 实例共享,所以不要使用它来清理局部变量。
"ms-help://MS.VSCC/MS.MSDNVS.2052/cpguide/html/cpconworkingwithhttpapplicationinstances.htm这是MSDN中对 HttpApplication 类的Init和Dispose方法的建议,其中“局部变量不被多个 HttpApplication 实例共享”这一句就是对你对同步应用程序对象的疑惑的解释,实际Asp.Net做了很简单的方法来处理,也就是根本就不同步实例字段,所以它也建议了,如果要保存全局的数据,使用Global中的局部变量是不可以的,使用HttpApplicationState才是正确选择