Spring单例模式的一次失败经历和总结

Spring单例模式的一次失败经历和
 今天看到一个网友骂Spring singletom是个骗子,所以进去仔细看了。
原文如下
这次被骗代价十分惨重,特此分享以警后人。
简单说说这次经历。事情发生在2006年7月6日。

我们准备设计log系统。采用p6spy,我们订制了一个自己的log输出类。每次logclass生成一个实例,就把他加进一个Set中。在读取sql log的时候,我们使用一个静态方法从一个维护logobject的Set中读出一个logobject,使用这个实例来输出。原则上多线程的操作是要同步的,但是考虑到效率问题,头们决定只是在生成一个logclass实例并向Set中添加时进行同步,而读取时不进行同步。原因就是,我们把 logclass设置成了单态,也就是原则上它只有一个实例。即使多个应用同时启动,也只有固定数量的实例。而这些实例都应该随着web启动而全部预加载。好,大头拍板了,就这么干。

于是,一个恶根被埋下,并在不知不觉地生长。两年来以半年左右一次的频率,一个Exception不断撩拨着我们的神经。客户那边随着 exception的发生也不断有人来问不过开发人员谁也没有在意,毕竟这个例外很友好,它发生在log输出阶段,发生之后会缺失一段log,不过这不算什么影响,大家都以为不用去管,看这个还不如去喝喝茶聊聊天。
今年9月,也就是这个月初。客户突然要求对这个不知所谓的东西严密调查,不然就怀疑我们框架的严密性。好家伙,这些平时温和的客户终于爆发了。好吧,调查。

首先跟踪log.发现在发生这个ConcurrentModificationException发生之前有一次类加载。难道类被重新加载了?如果类被重新加载,基于我对springsingleton的误解,于是我做了一个误判。那就是类被gc掉了。这当然不是没有可能的,如果长时间的闲置,类被回收那么类的静态量就会被重置,那么如果一个线程访问中间静态量被重置的话,那么就极有可能发生异常。我这样判断还有一个原因,springsingleton的类实例只有一个,而我用的都是静态方法,也就是没有引用实例,如果gc,那么这个类的实例很可能被收调,没有实例引用,静态量引用不足以阻止gc。于是接下来我这对我的推断作了一个周的实验,强制gc作了n多遍,无果。我开始对自己的判断产生怀疑,于是仔细察看代码和 log。突然发现几个异常出现都是在web service 开始的一段时间。难道是web service搞得鬼?于是打开web service源代码。一个异常点展现在我面前。每次调用web service,他都会将用到的类重新加载,包括logclass.这样就产生了新的推论。某个线程在访问log class的静态量Set时由于webservice的加载使得set发生变化从而引发异常。试验一下果然如此。

人说千里之堤溃于蚁穴看来不假。如此小的问题竟使得别人对我们的框架产生怀疑,可叹。

总结一下,spring singleton的含义是在一个spring 上下文中保持单态,如果一个jvm上多次加载spring context将使得单态的意义不复存在,与此会产生同步等问题。希望能给大家一些参考。


个人观点:
每次调用web service,他都会将用到的类重新加载,包括log class.

这个是关键。为何每次都会重新加载?

我们看一下Spring的工厂方法。 我们指定了一个application.xml作为配置文件。

如果我们有2个工厂方法呢?他们是2套完全不同的配置,那么所谓的单例还存在吗?


呵呵,不用猜,他们各自使用各自的,不会互相干扰的。

所以。单例一定要在类一级实现,不要指望Spring给你实现。如此,也只能保证一个Context下面的类是单例的。

如果有虚拟主机,虚拟目录,他们的ClassLoader是独立的,同样无法实现单例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Spring框架中的单例模式可以在BeanFactory接口中找到默认的单例Bean实现。这意味着Spring框架会默认将Bean实例化为单例对象,确保在整个应用程序中只有一个对象实例存在。这种单例模式的设计使得我们可以在不同的地方使用同一个Bean实例,避免了资源的浪费和重复创建对象的开销。此外,在Spring框架中还有其他的单例模式实现方式,比如使用静态内部类或者枚举方式。这些实现方式都可以保证在Spring应用程序中只有一个实例存在,从而提高了应用程序的性能和效率。所以,Spring框架中的单例模式是一种常见且有效的设计模式,可以帮助我们更好地管理和使用对象实例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [浅谈Spring框架应用的设计模式(二)——单例模式](https://blog.csdn.net/weixin_44420511/article/details/125205035)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [SpringBoot的单例模式特点(详细版)](https://blog.csdn.net/m0_71507863/article/details/129614975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值