【问题标题】:How Singleton Pattern works in a web scope?单例模式如何在 Web 范围内工作?
【发布时间】:2011-10-09 20:22:30
【问题描述】:

我知道单例模式的工作原理,但我怀疑它在网络范围内的工作原理。不是自然应要求吗?

发出请求并实例化单例并且请求已结束。单身被毁了?如果是,为什么有些人要明确地让单例进入请求范围?如果没有,会发生什么?单例保留在内存中,并为每个请求创建一个新的?

更新:

当我说“为什么有些人要明确地让单例进入请求范围”时,例如使用 Ninject 我必须这样做:

Bind<ISession>().To(SessionSingleton.Instance).InRequestScope();

更新 2:

using System;

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
}

更新 3:

我的DbContext 是单身?我认为不,我的DbContextFactory 是单例的,但是在这种情况下我的DbContext 将在请求结束时被销毁?

public class DbContextFactory
{
    #region Fields

    private static volatile DbContextFactory _dbContextFactory;
    private static readonly object SyncRoot = new Object();
    public DbContext Context;

    #endregion

    #region Properties

    public static DbContextFactory Instance
    {
        get
        {
            if (_dbContextFactory == null)
            {
                lock (SyncRoot)
                {
                    if (_dbContextFactory == null)
                        _dbContextFactory = new DbContextFactory();
                }
            }
            return _dbContextFactory;
        }
    }

    #endregion

    #region Methods

    public DbContext GetOrCreateContext()
    {
        if (this.Context == null)
            this.Context = new DbContext(ConfigurationManager.AppSettings["DefaultConnectionString"]);

        return Context;
    }

    #endregion
}

【问题讨论】:

  • 如果你还没有被告知,几乎所有单身人士都是邪恶的。
  • 什么语言/平台/框架?

标签: .net design-patterns web-applications singleton


【解决方案1】:

即使在 Web 应用程序的上下文中,也存在具有全局范围的对象。其中之一是由框架创建的 System.Web.HttpApplication。静态实例也具有全局范围。这些全局对象的生命周期与您的应用程序的生命周期相关(而不是网络请求)。该框架可能会停止并启动您的应用程序(想想应用程序池回收)。

在 Web 应用程序的上下文中,单例也具有全局范围,因此它们与应用程序的生命周期相关联,并且不会在每个请求结束时被销毁。当 Web 应用重新启动时,它们可能会被销毁并重新创建,但这不应计入您的应用。

另外补充一下其他人所说的,单例通常是邪恶的,你应该在设计单例之前三思而后行,除非它们正是你需要的。您可能希望确保只有一个实例的一些示例包括日志记录、缓存、NHibernate 的会话工厂和其他跨领域基础设施组件,以及仅作为一个实例存在的资源模型。

【讨论】:

  • @lulian 请查看我的更新...由于 static 关键字,我的单例类具有全局范围?
  • 是的,使用静态使实例字段具有全局范围。但是你的实现有一些问题——记住所有并发请求的所有线程都将访问你的单例的同一个实例。我不会详细介绍 - 如果您需要,请使用 Google 进行单例实现。至少将其更改为 private static Singleton instance = new Singleton();并且在 Instance 属性中只返回 Singleton.instance。还要记住 Singleton 类的所有公共方法必须是线程安全的。如果你有时间考虑不使用单例:)
  • 你的 DbContextFactory 确实是一个单例。但是您创建 DbContext 的方式是错误的。首先,在第一次调用 GetOrCreateContext 时,只创建了一个 DbContext。正如我在上一条评论中所说,单例中的所有方法都必须是线程安全的。 GetOrCreateContext 方法不是线程安全的。您还假设 DbContext 字段将在请求结束时被销毁,这是错误的。在请求结束时不会破坏上下文或将其设置为 null。
  • 如果您想要实现的是每个请求的数据库上下文,那么单例不适合。您可以使用支持每个 Web 请求对象生命周期的 IOC 容器,也可以在 HttpApplication.BeginRequest 事件上创建一个新上下文,将其存储在 HttpContext.Current.Items 中并在 EndRequest 事件上处理它。谷歌应该有关于每个请求 linq2sql 上下文的更多细节
  • 但是看看我的 DbContext 对象,它不是静态的,它没有全局范围,垃圾收集器在你使用结束时被销毁,我错了吗?我不明白会发生什么......
【解决方案2】:

正如 Raynos 所说:单身人士邪恶的。

但回答您的问题,单例不会因每个请求而被实例化或销毁,但它会保留在内存中并在所有请求之间共享,无论何时发出请求。

我不完全理解你的意思是什么为什么有些人会明确地让单例进入请求范围?。你在谈论一个特定的框架吗? (出于某种原因,我觉得你在谈论春天)。你能举例说明你指的是什么吗?

【讨论】:

  • 请查看更新。但是当我的请求结束时,所有对象都被 .Net 中的垃圾收集器销毁?
猜你喜欢
  • 2012-07-06
  • 1970-01-01
  • 2011-09-08
  • 1970-01-01
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多