spring singleton 你这个骗子!!!

Gump09 2008-09-26 09:27:43
这次被骗代价十分惨重,特此分享以警后人。
简单说说这次经历。事情发生在2006年7月6日。
我们准备设计log系统。采用p6spy,我们订制了一个自己的log输出类。每次log class生成一个实例,就把他加进一个Set中。在读取sql log的时候,我们使用一个静态方法从一个维护log object的Set中读出一个log object,使用这个实例来输出。原则上多线程的操作是要同步的,但是考虑到效率问题,头们决定只是在生成一个log class实例并向Set中添加时进行同步,而读取时不进行同步。原因就是,我们把log class设置成了单态,也就是原则上它只有一个实例。即使多个应用同时启动,也只有固定数量的实例。而这些实例都应该随着web启动而全部预加载。好,大头拍板了,就这么干。
于是,一个恶根被埋下,并在不知不觉地生长。两年来以半年左右一次的频率,一个Exception不断撩拨着我们的神经。客户那边随着exception的发生也不断有人来问不过开发人员谁也没有在意,毕竟这个例外很友好,它发生在log输出阶段,发生之后会缺失一段log,不过这不算什么影响,大家都以为不用去管,看这个还不如去喝喝茶聊聊天。
今年9月,也就是这个月初。客户突然要求对这个不知所谓的东西严密调查,不然就怀疑我们框架的严密性。好家伙,这些平时温和的客户终于爆发了。好吧,调查。
首先跟踪log.发现在发生这个ConcurrentModificationException发生之前有一次类加载。难道类被重新加载了?如果类被重新加载,基于我对spring singleton的误解,于是我做了一个误判。那就是类被gc掉了。这当然不是没有可能的,如果长时间的闲置,类被回收那么类的静态量就会被重置,那么如果一个线程访问中间静态量被重置的话,那么就极有可能发生异常。我这样判断还有一个原因,spring singleton的类实例只有一个,而我用的都是静态方法,也就是没有引用实例,如果gc,那么这个类的实例很可能被收调,没有实例引用,静态量引用不足以阻止gc。于是接下来我这对我的推断作了一个周的实验,强制gc作了n多遍,无果。我开始对自己的判断产生怀疑,于是仔细察看代码和log。突然发现几个异常出现都是在web service 开始的一段时间。难道是web service搞得鬼?于是打开web service 源代码。一个异常点展现在我面前。每次调用web service,他都会将用到的类重新加载,包括log class.这样就产生了新的推论。某个线程在访问log class的静态量Set时由于web service的加载使得set发生变化从而引发异常。试验一下果然如此。
人说千里之堤溃于蚁穴看来不假。如此小的问题竟使得别人对我们的框架产生怀疑,可叹。
总结一下,spring singleton的含义是在一个spring 上下文中保持单态,如果一个jvm上多次加载spring context将使得单态的意义不复存在,与此会产生同步等问题。希望能给大家一些参考。

...全文
1078 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
Johnzhao88 2010-05-10
  • 打赏
  • 举报
回复
值得好好学习!~经验是最宝贵的!~多谢!~~
YuLimin 2008-10-03
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 Gump09 的回复:]
项目的想法其实很简单。一个web应用,几个webservice,一套db监听,一套sql后台
sql后台是调sql,shell的。db监听定时同其他系统同步数据。所以都不需要加载上下文。
需要的就是一个web应用和几个webservice.设计上原来是没有问题的。
web启动时加在web应用和webservice的上下文。
不过由于编程错误,webservice上下文写在了webservice主类的调用方法里,而不是构造函数里
造成了每次调用webservice都要加载一次上下文。…
[/Quote]

那就是自己是骗子了?:)
sunyujia 2008-10-03
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 YuLimin 的回复:]
引用 27 楼 Gump09 的回复:
项目的想法其实很简单。一个web应用,几个webservice,一套db监听,一套sql后台
sql后台是调sql,shell的。db监听定时同其他系统同步数据。所以都不需要加载上下文。
需要的就是一个web应用和几个webservice.设计上原来是没有问题的。
web启动时加在web应用和webservice的上下文。
不过由于编程错误,webservice上下文写在了webservice主类的调用方法里,而不是构造函数里
造成了每次调用web…
[/Quote]
由于编程错误
被楼主骗进来了,呵呵.
spring的依赖注入的bean当然不是jvm级别的单例了.
Gump09 2008-09-29
  • 打赏
  • 举报
回复
项目的想法其实很简单。一个web应用,几个webservice,一套db监听,一套sql后台
sql后台是调sql,shell的。db监听定时同其他系统同步数据。所以都不需要加载上下文。
需要的就是一个web应用和几个webservice.设计上原来是没有问题的。
web启动时加在web应用和webservice的上下文。
不过由于编程错误,webservice上下文写在了webservice主类的调用方法里,而不是构造函数里
造成了每次调用webservice都要加载一次上下文。
看来对大家是一个小问题。嗬嗬,献丑了。
lhf0000 2008-09-29
  • 打赏
  • 举报
回复
学习中。。。
fireinjava 2008-09-29
  • 打赏
  • 举报
回复
似懂非懂,楼主辛苦了,学习
wufongming 2008-09-29
  • 打赏
  • 举报
回复
学习
guodingdongzyl 2008-09-29
  • 打赏
  • 举报
回复
很好的经验
nhy520 2008-09-28
  • 打赏
  • 举报
回复
专业
hcz202202 2008-09-28
  • 打赏
  • 举报
回复
学习...
YuLimin 2008-09-28
  • 打赏
  • 举报
回复
每次调用web service,他都会将用到的类重新加载,包括log class.这样就产生了新的推论。某个线程在访问log class的静态量Set时由于web service的加载使得set发生变化从而引发异常。试验一下果然如此。

每次调用都会将用到的类重新加载?是你的问题吧。。。

详细说说项目的情况。。。:)
Sou2012 2008-09-28
  • 打赏
  • 举报
回复
学习一下。
笨沙发 2008-09-28
  • 打赏
  • 举报
回复
本身就是一个上下文中保持单态吧,我被楼主骗了
wangshuilang11 2008-09-28
  • 打赏
  • 举报
回复
太专业了!
ptx7639 2008-09-27
  • 打赏
  • 举报
回复
支持。。。。。。。。
skyhits1921 2008-09-27
  • 打赏
  • 举报
回复
是啊,怎么webcontext还会被回收吗?
ycnanevol 2008-09-27
  • 打赏
  • 举报
回复
小问题跟没问题还是有点区别的,呵呵
JustLook_ 2008-09-27
  • 打赏
  • 举报
回复
不懂 学习````。。。。。.
shujianhua 2008-09-27
  • 打赏
  • 举报
回复
学习。。。。
提个问题,
spring context多次加载 是什么情况?
老紫竹 2008-09-27
  • 打赏
  • 举报
回复
。每次调用web service,他都会将用到的类重新加载,包括log class.这样就产生了新的推论

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

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

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


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

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

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

加载更多回复(14)

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧