单例模式如何在 Web 环境中工作?

Posted

技术标签:

【中文标题】单例模式如何在 Web 环境中工作?【英文标题】:How do singleton patterns work in a web context? 【发布时间】:2012-07-06 22:06:48 【问题描述】:

所以,使用单例模式的对象只能有一个实例。这在网站上如何运作?

问题:

    对于网站的每个客户/访问者来说,单例对象是唯一的吗?即单例对象是否每个客户端都有一个实例? Web 应用程序中的对象仅持续几秒钟,因此如果两个客户端同时访问一个网站,则两个客户端都将尝试创建一个单例对象。这是否意味着会抛出一个访问者会看到的异常?我尝试谷歌搜索,但找不到直接的答案。我只是想澄清一下。

【问题讨论】:

【参考方案1】:

史蒂夫,我会尽力回答你的每一个问题:

1) 对于 Web 开发,将对象限定为 Web 请求是很常见的(有时这也称为“每个请求上下文”或“每个 http 上下文”),但我们通常不提及这些由于这个确切的原因,作为单身人士。事实上,大多数 IOC 容器都内置了一个开箱即用的“每个 Web 请求”范围以及一个“单例”。

2) 有时,Web 应用程序也有真正的单例(所有请求都可以访问)。如上所述,这并不完全正确,因为它将被限定在应用程序池中,并且在/如果重新启动应用程序池时会被吹走。但对于 Web 应用程序而言,这是一个单例。正如 Jigar 所提到的,有时以这种方式设置诸如日志记录等“横切关注点”。这些通常不会在每个 Web 请求中初始化,而是在 global.asax 中或依靠 IOC 容器为您执行此操作。您只需确保在执行对​​象创建时使用标准锁定模式之一来防止两个线程/客户端/等...同时创建对象。这是来自 Microsoft 的链接,但也有其他实现:http://msdn.microsoft.com/en-us/library/ff650316.aspx 如果您使用的是流行的 IOC 容器之一,它将为您解决这个问题(Structuremap、Windsor、Autofac、Unity、Ninject ......许多其他人)。

您需要询问您的同事他们指的是哪种方法,因为这两种方法在某些情况下都有效并且非常常见。

【讨论】:

【参考方案2】:

这完全取决于您的单例实现。在这里,我假设您将单例创建为在静态构造函数中初始化的静态字段。

理论上,根据其设置,IIS 可能会为您的应用程序创建多个进程,并且每个进程可以创建多个线程来处理请求。每个进程都有自己的单例,可以共享多个线程(和多个请求)。但是同时在一台服务器上可以有多个“单例”实例(每个进程一个)(但是,如果我理解正确,可以在 IIS 设置中禁止多个进程)。

如果您使用静态构造函数,那么在第一次访问您的类时会以线程安全的方式创建单例。见Is the C# static constructor thread safe?

虽然单例创建是线程安全的,但您仍然必须以线程安全的方式实现单例类的内部。

Singleton 将在您的应用程序进程存在且未重新启动时存在。应用进程的生命周期由 IIS 管理,可以是很长的时间,也可以是很短的时间。

【讨论】:

【参考方案3】:

单例由 IIS 维护,因此单例的持续时间与 IIS 应用程序池一样长。一旦它被回收或 IIS 被重置,那么单例就会消失。您需要锁定单例以进行多次访问。就像在任何其他客户端服务器应用程序中一样。

通常我会尽量避免它,因为它有点违背网站本质上是无状态客户端服务器应用程序的想法。为什么不直接使用 Session 来存储任何共享数据?

【讨论】:

我刚开始在一家公司的网络部门实习,无意中听到一些同事在网络环境中谈论单身人士,我很困惑。这不是我目前正在实施的。 如何使用会话存储共享数据?【参考方案4】:

对于记录器和共享资源,我们肯定可以在 Web 应用程序中使用单例。正如 Liam 所说,只要您的应用程序池未被清除,它们就会一直存在。

为了更好地理解,请访问...http://www.oodesign.com/singleton-pattern.html

谢谢

【讨论】:

看起来不像一个完整的答案。本来可以更好的评论 down-vote :( 好吧可能不是一个完整的答案,没有人接受,但提出问题的人可以说一个完整或不完整的答案。虽然需要认真【参考方案5】:
public class SingletonContext<TContext>
    where TContext: DbContext,new()

    private static TContext _context;

    private SingletonContext()
    

    
    public static TContext GetInstance()
    
        if (_context == null)
        
            _context = new TContext();
        
        return _context;
    


【讨论】:

所以,有两件事。 1)不能有人只是new MyDbContext()吗?这并不能阻止两个。 2)我认为你这样做是因为你不想new 一堆相同的上下文,但这最好在你的 IoC 容器中处理

以上是关于单例模式如何在 Web 环境中工作?的主要内容,如果未能解决你的问题,请参考以下文章

hashTable 和 hashMap 作缓存,实现的两种单例的区别

用故事的形式趣说Python单例模式

Singelton单例模式

单例模式 --- 生产环境怎么写#yyds干货盘点#

php 设计模式之单例模式

如何保证单例模式在多线程中的线程安全性